C++11 move semantic simple example

26 Apr 2014

There is plenty of long, detailed articles online about C++11 r-value references, move semantic and move constructors so I won’t bother you going into so much detail here. Instead I am going to discuss a simple example on how useful this “new” C++11 feature is and how it helps in writing better, more intuitive C++ code.

Suppose you are writing a function that processes a file to send it or parse it or whatever. Before C++11 one would declare a function prototype like so:

1
2
3
4
5
void do_something_with_file (std::ifstream& file);
.
.
std::ifstream file("/path/to/some/file"); // open the file here
do_something_with_file(file);

or like this

1
void do_something_with_file (std::string filename);

but you can’t write something like this:

1
2
3
4
5
void do_something_with_file (std::ifstream file);
.
.
std::ifstream file("/path/to/some/file");
do_something_with_file(file);

This call won’t compile (line 5) because we can’t copy std::ifstream objects (There is copy because we are passing the argument by value). The compiler will complain because the copy ctor of std::ifstream is marked as private in old C++ and is implicitly deleted as we will see later with C++11. And this is where the move semantic of C++11 comes into play. Now we can define our function in this way:

1
2
3
4
5
6
7
void do_something_with_file (std::ifstream && file) {
    std::string s;
    while (file) { // uses bool operator () of std::ifstream 
        std::getline(file, s);
        std::cout << s << "\n";
    }
}

Notice the syntax used to declare the function parameter file: the double &. It means that the function takes a so called r-value reference. Now the function is called in this way:

1
do_something_with_file(std::ifstream("file.txt"));

This code creates a temporary object std::ifstream("file.txt") directly at call site. This temporary is used to create the function paramater using the move ctor of std::ifstream and not the copy ctor as it is now deleted. The move ctor actually takes ownership of the resources held by the temporary. Moreover, we no longer need to declare an std::ifstream object to open the file as a first step, then pass it by reference to our function which feels awkward. Now the code feels more natural and straightforward: the function takes a file then we just call it passing it a file argument. Of course you still can pass an l-value as argument to the function if you absolutely have to, using the std::move utiliy:

1
2
std::ifstream file("/path/to/some/file");
do_something_with_file(std::move(file));

But this defeats the point of the post ;)

comments powered by Disqus