7

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.

  • 3
    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. – ShadowRanger Apr 04 '17 at 01:25
  • 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`) – Dustin Nieffenegger Apr 04 '17 at 01:31
  • Possible duplicate of [What is std::move(), and when should it be used?](http://stackoverflow.com/questions/3413470/what-is-stdmove-and-when-should-it-be-used) – Andria Apr 04 '17 at 01:34
  • 1
    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? – Dustin Nieffenegger Apr 04 '17 at 01:53
  • Be kind of disappointed if the compiler didn't see the pass by value in the parameter and take advantage without prodding. – user4581301 Apr 04 '17 at 03:28
  • You have a third alternative, provide `A( std::string&& )`. – Jarod42 Apr 04 '17 at 11:15
  • *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. – ComicSansMS Apr 15 '20 at 10:56

2 Answers2

4

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
Andrei Matveiakin
  • 1,558
  • 1
  • 13
  • 17
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.

Pavan Chandaka
  • 11,671
  • 5
  • 26
  • 34
  • 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. – Christopher Oicles Apr 04 '17 at 02:12
  • Isn't Example A slightly better because it doesn't use a reference as an intermediary to create the copy? – Dustin Nieffenegger Apr 04 '17 at 02:33
  • 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"?? – Pavan Chandaka Apr 04 '17 at 02:55