Frage

Suppose that there is a Person class like this:

// "string" is std::string, "move" is std::move

class Person
{
public:
    // C++11 way: pass by value and std::move() from the value
    Person(string name, string surname)
        : m_name(move(name)), m_surname(move(surname))
    {}

    ....

private:
    string m_name;
    string m_surname;
};

Suppose that I read the name and surname values from some source (e.g. a file) in some loop, and in each loop iteration I want to create a Person with these read values (and e.g. push the created Person in some container).

Is it better to call Person constructor in the usual way:

Person(name, surname)

or using std::move for the arguments?

Person(move(name), move(surname))
War es hilfreich?

Lösung

I'd recommend against making this complicated by choosing to use Person(move(name), move(surname)) without a particular reason for doing so.

Consider a simple loop reading names and constructing Person objects:

string name, surname;
while ((cin >> name) && (cin >> surnam)) {
  Person p(name, surname);
  // ...
}

This does result in copies of name and surname for each Person, but the allocation behavior in this context actually turns out to be efficient. Since name and surname retain their own buffers, those buffers just get reused for the next input operation, which means that once those buffers are large enough no additional allocations occur just for the input. So on average you should get just the one allocation per name and surname that occurs during the copy.

If you use move() to save the one allocation during the copy, then allocation is done during the input operation instead and you can possibly get multiple allocations as the buffer grows dynamically while reading. That means you could potentially do many more allocations when using move().

Furthermore, the copy allocates the minimal amount of memory needed, whereas the strings used in the input operation may have 'extra' based on whatever dynamic growth strategy string employs. Therefore explicit moves could result in greater memory usage by persisting that 'extra' into the Person objects.


So by default just do what's simple and straightforward. I think using move() by default here is a case of premature optimization.

Andere Tipps

The second way if you no longer need name or surname. If you still need one of them however then you should use the first (or move one but not the other).

Either way, the only constructor is called and a copy of the arguments is done. What you really 'need' is a second constructor accepting rvalue references (in fact it takes 3 additional constructors to be optimal in this case for all the combination of rvalue/lvalue). Then you'd be able to move/forward the arguments to the constructor and get reel benefits.

Nevermind, this is wrong. C++11 way = pass-by-value-then-move when you know you'll need a copy at some point. This saves time and energy as you don't have to write rvalue overloads.

As already mentioned, you should not move variables you want to access later.

Edit: See this related question : C++11 Const reference VS move semantics

You've declared your constructor to take copies rather than reference, so you're creating a new object whenever you call the constructor. You'd be better off passing by reference:

Person(const string &name, const string &surname)
        : m_name(name), m_surname(surname)

You're still doing the same number of object constructions as before, but now you're no longer using std::move.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top