Should I write constructors using rvalues ​​for std :: string?

I have a simple class:

class X { std::string S; X (const std::string& s) : S(s) { } }; 

I read a bit about rvalues ​​lately, and I was wondering if I should write a constructor for X using rvalue, so I could detect temporary objects like std::string ?

I think it should look something like this:

 X (std::string&& s) : S(s) { } 

As far as I know, the implementation of std :: string in compilers that support C ++ 11 should use it when moving the constructor.

+14
c ++ string constructor c ++ 11 rvalue-reference
May 31 '12 at 15:05
source share
4 answers
 X (std::string&& s) : S(s) { } 

This is not a constructor that accepts an rvalue, but a constructor that accepts an rvalue-reference. In this case, you should not take rvalue links. Rather pass the value and then go to the element:

 X (std::string s) : S(std::move(s)) { } 

The rule of thumb is that if you need to copy, do it in the interface.

+23
May 31 '12 at 15:10
source share

In the interest of clarification: the answers to the amendment are not mistaken. But not one of your first assumptions about adding string&& overload except one detail:

Add

 X (std::string&& s) : S(std::move(s)) { } 

those. you still need to move , because although s has the declared type of the rvalue reference to string , the expression s , used to initialize s , is an lvalue expression of type string .

In fact, the solution you first proposed (with added movement) is a bit faster than the solution with a transition by value. But both are correct. The pass-by-value solution invokes the line move constructor in extra time when passing the lvalue and xvalue arguments to the X constructor.

In the case of lvalue arguments, the copy is executed anyway, and the string copy constructor is likely to be much more expensive than the line move constructor (except for the lines that fit into the buffer of short lines, in which case moving and copying at about the same speed) .

In the case of xvalue arguments (the value of x is the value of l that was passed to std::move ), solving the step-by-step solution requires two move constructs instead of one. Thus, it is twice as expensive as going through the rvalue reference solution. But still very fast.

The point of this article is to make it clear: bandwidth is an acceptable solution. But this is not the only acceptable solution. Overloading with pass-by-rvalue-ref is faster, but has the disadvantage that the number of overloads required to scale is 2 ^ N as the number of N arguments increases.

+19
May 31 '12 at 15:59
source share

No, not worth it. What you have to do is replace your current constructor with the following:

 X (std::string s) :S(std::move(s)) {} 

Now you can handle both l values ​​that will be copied to the parameter and then transferred to the line of your class and r values ​​that will be moved twice (your compiler, I hope, can optimize this extra work).

For the most part (there are exceptions to which I will not go), you should not write functions that take r-value references, with the exception of the class movement constructors you write. Every time you need your own copy of a value, and this does not apply to just constructors, you must take it by value and move it to where it needs to go. You let your own move constructor decide whether to copy or move the value depending on whether it gets the value of r or the value of l. At the end, r-value links were introduced to make our life easier, not harder.

+13
May 31 '12 at 15:09
source share

Since you need a copy of the argument, take the parameter by value. Then move it to member data. This is the std::string constructor, which is responsible for detecting whether the given argument is an rvalue or lvalue value, and not you.

 class X { std::string s_; X(std::string s) : s_(std::move(s)) {} }; 
+5
May 31 '12 at 15:10
source share



All Articles