Should I always use std::move in a constructor?
Asked Answered
M

2

8

Are the move semantics used in Example A necessary, and which struct is superior?

Example A:

struct A
{
    std::string a;
    A( std::string a ) : a( std::move(a) ){ }
};

Example B:

struct B
{
    std::string b;
    B( const std::string& b ) : b( b ){ }
};

I don't believe this is a duplicate question. I am asking specifically which example is superior from the perspective of using member initialization in a class constructor. None of the examples or answers listed in the other question dealt with member initialization.

I don't like that the constructor is called with a reference parameter, then copied into the member. It seems that it could be wasteful to have multiple copy operations.

I want to "pipe" the data into the members as efficiently as possible but I don't want to take rvalues as the constructor parameters.

Madalene answered 4/4, 2017 at 1:24 Comment(7)
If the value is an int or other single value primitive, using either move or references (const or otherwise) is pointless. Also, I'd consider the struct without an explicit constructor superior in this case, what with aggregate initialization working just fine here.Holms
I used int for simplification of the example. If it were std::string or any other more complicated class, which would be superior? (edited my answer and changed int to be std::string)Madalene
Possible duplicate of What is std::move(), and when should it be used?Comte
I don't believe this is a duplicate. None of the answers or questions dealt with member initialization. If you look at example A, it creates a copy in the parameter then moves it into the member. In example B, it creates a reference, then copies it in the member. So, example B would have two copy operations while example A would only have one, correct?Madalene
Be kind of disappointed if the compiler didn't see the pass by value in the parameter and take advantage without prodding.Criminality
You have a third alternative, provide A( std::string&& ).Devin
It seems that it could be wasteful to have multiple copy operations. - I count exactly one copy for the second case. The first case is the wasteful one, as it will do a copy construct+move construct to perform what is essentially a copy.Bronwyn
M
5

Struct A is superior.

Moving an object is usually very cheap (and can often be completely optimized out), so typically one shouldn't care about the number of moves. But it's important to minimize the number of copies. The number of copies in example A is equal to or less than the number of copies in example B.

More specifically, A and B are equivalent if the original string is an L-value:

std::string s;
...
A a(s);  // one copy
B b(s);  // one copy

but A is better when the original string is an R-value:

std::string MakeString();
...
A a(MakeString());  // zero copies
B b(MakeString());  // one copy
Marchland answered 15/4, 2020 at 10:50 Comment(0)
N
1

In my opinion it is not genuine to compare both.

Most of the times the implemented copy constructor makes deep copy and the main intention behind is to ensure the source object is not modified.

std::move which eventually calls move constructor for rvalue reference, just copies the pointer and can set the source object pointer to NULL. This scenario is mainly for temporary objects.

So both examples are meant for two different purpose, one (copy constructor) when you want source object to be untouched, and the other (std::move) is meant for dealing temporary objects.

Nellynelms answered 4/4, 2017 at 2:0 Comment(3)
But the parameter is passed by value in the std::move case, so std::string's copy constructor is used to create a temporary object, which is then moved into the member variable -- so as far as I can tell, the two cases are equivalent, and which to choose is just a matter of style.Phalanger
Isn't Example A slightly better because it doesn't use a reference as an intermediary to create the copy?Madalene
Does example A has a copy constructor imementation also? Even If not default copy constructor is called when you pass by value. So in example A won't it be like "a complete copy constructor call + std::move"??Nellynelms

© 2022 - 2024 — McMap. All rights reserved.