Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The C++11 way of initializing data members from arguments

Seeing as C++11 supports move semantics, when initializing data members from arguments, should we attempt to move the value instead of copying it?

Here's an example showing how I would approach this in pre-C++11:

struct foo {
    std::vector<int> data;

    explicit foo(const std::vector<int>& data)
        : data(data)
    {
    }
};

Here, the copy constructor would be called.

In C++11, should we get into the habit of writing like this:

struct foo {
    std::vector<int> data;

    explicit foo(std::vector<int> data)
        : data(std::move(data))
    {
    }
};

Here, the move constructor would be called... as well as the copy constructor if the argument passed is an lvalue, but the benefit is that if an rvalue was passed, the move constructor would be called instead of the copy one.

I'm wondering if there's something I'm missing.

like image 394
someguy Avatar asked Aug 21 '11 12:08

someguy


People also ask

Can we initialize data members in a class C?

In C++11, the language has been extended to allow specifying an initializer in the declaration, but this is just a shorthand—the actual initialization still takes place at the top of the constructor. Initialization of data members will also still occur in order of declaration.

How do you initialize a class member in C++?

There are two ways to initialize a class object: Using a parenthesized expression list. The compiler calls the constructor of the class using this list as the constructor's argument list. Using a single initialization value and the = operator.

How can we initialize data members of any class illustrate?

For the static variables, we have to initialize them after defining the class. To initialize we have to use the class name then scope resolution operator, then the variable name. Now we can assign some value. The following code will illustrate the of static member initializing technique.


3 Answers

My initial answer to your question was:

Don't copy data that you want to move. You can add a constructor using a rvalue reference, if performance is a problem:

explicit foo(std::vector<int>&& data)
    : data(std::move(data))            // thanks to Kerrek SB
{
}

Not exactly matching your question, but reading Rule-of-Three becomes Rule-of-Five with C++11? seems to be useful.

Edit:

However, the accepted answer to Passing/Moving parameters of a constructor in C++0x seems to advocate your approach, especially with more than one parameter. Otherwise there would be a combinatorial explosion of variants.

like image 124
René Richter Avatar answered Oct 16 '22 18:10

René Richter


Passing by value in the copy constructor only helps when the argument is movable, otherwise you could end up with up to two copies (one for the argument passing, one for the member construction). So I'd say it's better to write a copy and a move constructor separately.

Passing by value makes sense for the assignment operator if you have a properly implemented swap function, though:

Foo & operator=(Foo other) { this->swap(std::move(other)); }

Now if other is moveable, Foo's move constructor comes in during argument construction, and if other is merely copyable, then the one necessary copy is made during argument construction, but in both cases you get to use the moving version of swap, which ought to be cheap. But this relies on the existence of a move constructor!

So note that out of "construction", "swap" and "assigment" you will have to implement two properly, and only the third can take advantage of the other two. Since swap should be no-throw, using the swap trick in the assigment operator is basically the only option.

like image 41
Kerrek SB Avatar answered Oct 16 '22 20:10

Kerrek SB


Yes, you are doing it correctly. Any time you need a copy of a value, do it in the parameters by passing by value.

The following is correct:

struct foo {
    std::vector<int> data;

    explicit foo(std::vector<int> data)
        : data(std::move(data))
    {
    }
};
like image 24
Benjamin Lindley Avatar answered Oct 16 '22 18:10

Benjamin Lindley