why use a move constructor? - c++

I'm a little confused as to why you would use/need a move constructor.
If I have the following:
vector fill(istream& is)
{
vector res;
for(double x; is >> x; res.push_back(x));
return res;
}
void bar()
{
vector vec = fill(cin);
// ... use vec ...
}
I can remove the need to return res, hence not calling the copy constructor, by adding vector fill(istream& is, vector& res).
So what is the point of having a move constructor?

Assume you next put you std::vector<T> into a std::vector<std::vector<T>> (if you think vectors shouldn't be nested, assume the inner type to be std::string and assume we are discussing std::string's move constructor): even though you can add an empty object and fill it in-place, eventually the vector will need to be relocated upon resizing at which point moving the elements comes in handy.
Note that returning from a function isn't the main motivator of move construction, at least, not with respect to efficiency: where efficiency matters structuring the code to enable copy-elision further improves performance by even avoiding the move.
The move constructor may still be relevant semantically, though, because returning requires that a type is either copyable or movable. Some types, e.g., streams, are not copyable but they are movable and can be returned that way.

In you example compiler might apply RVO - Return Value Optimization, this means you function will be inlined, so no return will take place - and no move semantics will be applied. Only if it cannot apply RVO - move constructor will be used (if available).
Before move semantics were introduced people were using various techniques to simulate them. One of them is actually returning values by references.

One reason is that using assignment operators makes it easier to grasp what each line is doing. If have a function call somefunction(var1, var2, var3), it is not clear whether some of them gets modified or not. To find that out, you have to actually read the other function.
Additionally, if you have to pass a vector as an argument to fill(), it means every place that calls your function will require two lines instead of one: First to create an empty vector, and then to call fill().
Another reason is that a move constructor allows the function to return an instance of a class that does not have a default constructor. Consider the following example:
struct something{
something(int i) : value(i) {}
something(const something& a) : value(a.value) {}
int value;
};
something function1(){
return something(1);
}
void function2(something& other){
other.value = 2;
}
int main(void){
// valid usage
something var1(18);
// (do something with var1 and then re-use the variable)
var1 = function1();
// compile error
something var2;
function2(var2);
}
In case you are concerned about effiency, it should not matter whether you write your fill() to return a value, or to take output variable as a parameter. Your compiler should optimize it to the most efficient alternative of those two. If you suspect it doesn't, you had better measure it.

Related

When do you need to explicitly call std::move and when not in cpp?

I'm working through Stroustrup's "Tour of C++ v2". It's certainly not a C++ beginner's book, but enjoyable.
I've had a google and look through SO but no joy on this one.
Now, I thought I understood when the compiler can utilise a move constructor, but clearly I don't. Here I show the move constructor and the function that I thought would use it. It doesn't. Only if I explicitly use std::move. Why is this? My understanding was that the local r would be "moved" implicitly on return.
template<typename T>
Vector<T>::Vector(Vector<T> && a) // move constructor
:elem{a.elem},sz{a.sz}{
a.elem=nullptr;
a.sz=0;
}
template<typename T>
Vector<T> moveVectorAfterAdd(const Vector<T> & v1, const Vector<T> & v2){
Vector<T> r = v1+v2;
return std::move(r);
//return r;
}
int main(void) {
Vector<double> v1(1);
Vector<double> v2=v1;
Vector<double> v3=v2;
Vector<double> v4=moveVectorAfterAdd(v1,v2);
return 0;
}
(As a side note, lldb won't let me even set a break point in the move constructor despite compiling with no optimizations if I don't actually use std::move.)
Any and all clarifications gladly received!
When do you need to explicitly call std::move and when not in cpp?
In short, and technically precise words: Use std::move when you have an lvalue that you want to be an rvalue. More practically: You would want to do that when there is a copy that you want instead to be a move. Hence the name std::move.
In the example, you return an automatic variable. There is no copy that can be avoided by using std::move because in the special case of returning an automatic variable, there will be a move even from an lvalue.
Here I show the move constructor and the function that I thought would use it. It doesn't.
Just because there is a move in the abstract machine, doesn't necessarily mean that there would be a call to the move constructor. This is a good thing because doing nothing can potentially be faster than calling the move constructor.
This is known as (Named) Return Value Optimization. Or more generally copy elision. Using std::move inhibits this optimization, so not only is it unnecessary in this case, but it is also counter productive.

Copy constructors with move-only, but cloneable types in member containers

Assume that we have two types, T1 and T2.
T1 isn't important except the following facts:
it isn't copy constructible
it has a move constructor
we have an excellent function with the signature T1 copy(T1 const& orig), which creates a copy.
T2 can be simplified to the following class:
// T2.h
class T2 {
public:
T2() { /* initializes the vector with something */ }
T2(T2 const& other);
private:
std::vector<T1> v;
}
// T2.cpp
T2::T2(T2 const& other) : ... {}
How would you implement this method, if you could only write to the ellipsis part, or to the global scope?
A simple real world use case - assuming the "you can't write anything between the curly braces" part is a real world restriction:
T1 is std::unique_ptr<anything>
copy is std::make_unique
anything has a copy constructor
I also have two additional requirements for the implementation:
performance. It shouldn't be (considerably) slower than the naive implementation with a for loop in the copy constructor's body.
readability. The entire point behind the question is to do something which is more clear/clean than the trivial for loop (e.g. imagine T2 with two or more member vectors).
And optional, but nice to have features:
something that's easily generalized to other containers
something that works with just iterators
something that's generic
A clarification: I know the question is trivially solvable with a std::vector<T1> copy_vec(std::vector<T1> const& orig) global function. Placing that function into an anonymous namespace within T2.cpp would also make it local, but I would argue against its readability, I think it wouldn't be better than the for loop at all. And it's clearly a bad solution if the copy constructor isn't in an implementation file but inlined in the header.
So a rephrasing of my question is:
Is there already something similar implemented, which I can just include?
If there is none, then why? I'm not saying I thought about every corner case, but I think this is something that possibly can be implemented in a nice generic way, and thanks to unique_ptr, it's a common enough case.
Nothing wrong with a naive loop:
v.reserve(other.v.size());
for (auto& elem : other.v) {
v.push_back(copy(elem));
}
That's plenty readable and optimal.
Though I guess the modern, clever solution with be to use range-v3:
T2(T2 const& other)
: v(other.v | view::transform(copy))
{ }
I'm not sure that's enough better than the loop to justify the additional complexity but YMMV.

Why not auto move if object is destroyed in next step?

If a function return a value like this:
std::string foo() {
std::string ret {"Test"};
return ret;
}
The compiler is allowed to move ret, since it is not used anymore. This doesn't hold for cases like this:
void foo (std::string str) {
// do sth. with str
}
int main() {
std::string a {"Test"};
foo(a);
}
Although a is obviously not needed anymore since it is destroyed in the next step you have to do:
int main() {
std::string a {"Test"};
foo(std::move(a));
}
Why? In my opinion, this is unnecessarily complicated, since rvalues and move semantic are hard to understand especially for beginners. So it would be great if you wouldn't have to care in standard cases but benefit from move semantic anyway (like with return values and temporaries). It is also annoying to have to look at the class definition to discover if a class is move-enabled and benefits from std::move at all (or use std::move anyway in the hope that it will sometimes be helpfull. It is also error-prone if you work on existing code:
int main() {
std::string a {"Test"};
foo(std::move(a));
// [...] 100 lines of code
// new line:
foo(a); // Ups!
}
The compiler knows better if an object is no longer used used. std::move everywhere is also verbose and reduces readability.
It is not obvious that an object is not going to be used after a given point.
For instance, have a look at the following variant of your code:
struct Bar {
~Bar() { std::cout << str.size() << std::endl; }
std::string& str;
}
Bar make_bar(std::string& str) {
return Bar{ str };
}
void foo (std::string str) {
// do sth. with str
}
int main() {
std::string a {"Test"};
Bar b = make_bar(a);
foo(std::move(a));
}
This code would break, because the string a is put in an invalid state by the move operation, but Bar is holding a reference to it, and will try to use it when it's destroyed, which happens after the foo call.
If make_bar is defined in an external assembly (e.g. a DLL/so), the compiler has no way, when compiling Bar b = make_bar(a);, of telling if b is holding a reference to a or not. So, even if foo(a) is the last usage of a, that doesn't mean it's safe to use move semantics, because some other object might be holding a reference to a as a consequence of previous instructions.
Only you can know if you can use move semantics or not, by looking at the specifications of the functions you call.
On the other side, you can always use move semantics in the return case, because that object will go out of scope anyway, which means any object holding a reference to it will result in undefined behaviour regardless of the move semantics.
By the way, you don't even need move semantics there, because of copy elision.
Its all sums up on what you define by "Destroyed"? std::string has no special effect for self-destroying but deallocating the char array which hides inside.
what if my destructor DOES something special? for example - doing some important logging? then by simply "moving it because it's not needed anymore" I miss some special behavior that the destructor might do.
Because compilers cannot do optimizations that change behavior of the program except when allowed by the standard. return optimization is allowed in certain cases but this optimization is not allowed for method calls. By changing the behavior, it would skip calling copy constructor and destructor which can have side effects (they are not required to be pure) but by skipping them, these side effects won't happen and therefore the behavior would be changed.
(Note that this highly depends on what you try to pass and, in this case, STL implementation. In cases where all code is available at the time of compilation, the compiler may determine both copy constructor and destructor are pure and optimize them out.)
While the compiler is allowed to move ret in your first snippet, it might also do a copy/move elision and construct it directly into the stack of the caller.
This is why it is not recommended to write the function like this:
std::string foo() {
auto ret = std::string("Test");
return std::move(ret);
}
Now for the second snippet, your string a is a lvalue. Move semantics only apply to rvalue-references, which obtained by returning a temporary, unnamed object, or casting a lvalue. The latter is exactly what std::move does.
std::string GetString();
auto s = GetString();
// s is a lvalue, use std::move to cast it to rvalue-ref to force move semantics
foo(s);
// GetString returns a temporary object, which is a rvalue-ref and move semantics apply automatically
foo(GetString());

Should I always move on `sink` constructor or setter arguments?

struct TestConstRef {
std::string str;
Test(const std::string& mStr) : str{mStr} { }
};
struct TestMove {
std::string str;
Test(std::string mStr) : str{std::move(mStr)} { }
};
After watching GoingNative 2013, I understood that sink arguments should always be passed by value and moved with std::move. Is TestMove::ctor the correct way of applying this idiom? Is there any case where TestConstRef::ctor is better/more efficient?
What about trivial setters? Should I use the following idiom or pass a const std::string&?
struct TestSetter {
std::string str;
void setStr(std::string mStr) { str = std::move(str); }
};
The simple answer is: yes.
The reason is quite simple as well, if you store by value you might either need to move (from a temporary) or make a copy (from a l-value). Let us examine what happens in both situations, with both ways.
From a temporary
if you take the argument by const-ref, the temporary is bound to the const-ref and cannot be moved from again, thus you end up making a (useless) copy.
if you take the argument by value, the value is initialized from the temporary (moving), and then you yourself move from the argument, thus no copy is made.
One limitation: a class without an efficient move-constructor (such as std::array<T, N>) because then you did two copies instead of one.
From a l-value (or const temporary, but who would do that...)
if you take the argument by const-ref, nothing happens there, and then you copy it (cannot move from it), thus a single copy is made.
if you take the argument by value, you copy it in the argument and then move from it, thus a single copy is made.
One limitation: the same... classes for which moving is akin to copying.
So, the simple answer is that in most cases, by using a sink you avoid unnecessary copies (replacing them by moves).
The single limitation is classes for which the move constructor is as expensive (or near as expensive) as the copy constructor; in which case having two moves instead of one copy is "worst". Thankfully, such classes are rare (arrays are one case).
A bit late, as this question already has an accepted answer, but anyways... here's an alternative:
struct Test {
std::string str;
Test(std::string&& mStr) : str{std::move(mStr)} { } // 1
Test(const std::string& mStr) : str{mStr} { } // 2
};
Why would that be better? Consider the two cases:
From a temporary (case // 1)
Only one move-constructor is called for str.
From an l-value (case // 2)
Only one copy-constructor is called for str.
It probably can't get any better than that.
But wait, there is more:
No additional code is generated on the caller's side! The calling of the copy- or move-constructor (which might be inlined or not) can now live in the implementation of the called function (here: Test::Test) and therefore only a single copy of that code is required. If you use by-value parameter passing, the caller is responsible for producing the object that is passed to the function. This might add up in large projects and I try to avoid it if possible.

Proper way to implement move semantics for class with std::vector of std::vector member

I have a class that has a member which is a vector of vectors. I would like to write a constructor for this class that takes an r-value reference to a single vector as an argument, and moves it into the member vector as a single element vector of the vector argument. So far I have:
class AClass
{
std::vector<std::vector<int>> member;
public:
AClass(std::vector<int> &&vec) : member(1)
{
member[0] = std::vector<int>(std::move(vec));
}
}
This seems to work correctly, but I am not sure if the std::move around vec is necessary. Or if the std::vector would have taken care of much of this for me had I written it a little differently.
It should be shorter to write:
member[0] = std::move(vec);
in order to invoke
vector<T,Allocator>& operator=(vector<T,Allocator>&& x);
As far as I know, explicit moving is necessary, because vec is not a rvalue (it is a named variable and can be used on the left side of operator=).
The way of doing this now is to just pass the value into the constructor by value, then moving it to where you want. So
AClass(std::vector<int> vec)
{
member.emplace_back(std::move(vec));
}
You don't need to care about whether the value is copy-constructed in, or if it was able to be moved into the constructor because it was an rvalue, or whatever. You just request, in the function definition, that you get your own copy of the item, and the language will give it to you as best it can.