I cannot compile the attached project because I deleted the move constructors.
Is this the expected behavior? Why does the compiler need the move constructors if it won't use it?
windows-visual studio 2015 14.0.25431.01 update3
#include <string>
#include <sstream>
#include <vector>
class poo {
public:
poo() = default;
poo(poo&&) = delete; //deleted function
virtual ~poo() = default;
poo operator +(const poo &a) const {
poo to_return;
to_return._s += a._s;
return to_return;
//moveconstructors.cpp(14): error C2280: 'poo::poo(poo &&)': attempting to reference a deleted function
}
private:
std::string _s;
};
int main(int, char **) {
poo a;
return 0;
}
EDIT 1: the same result happens after adding "poo (const poo &) = default;"
EDIT 2: the same result happens with windows-visual studio 2019 16.1.0 preview 2.0
EDIT 3: the same result happens after adding/modifying
poo(const std::string &s) : _s(s) {
}
poo operator +(const poo& a) const {
return poo(_s + a._s);
}
EDIT 4: it works fine with vs2019 and /std:c++17
A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying. For more information about move semantics, see Rvalue Reference Declarator: &&. This topic builds upon the following C++ class, MemoryBlock , which manages a memory buffer.
The new operator lets developers create an instance of a user-defined object type or of one of the built-in object types that has a constructor function.
A move constructor is executed only when you construct an object. A move assignment operator is executed on a previously constructed object. It is exactly the same scenario as in the copy case.
In the C++ programming language, the move assignment operator = is used for transferring a temporary object to an existing object. The move assignment operator, like most C++ operators, can be overloaded. Like the copy assignment operator it is a special member function.
poo(poo&&) = delete;
This line disables the move constructor, yes, but it also deletes the copy constructor.
From class.copy.ctor:
If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted;.
Now, all this wouldn't be a big deal if named return value optimization (NRVO) was guaranteed by the standard, because the compiler could see that your operator+
has a single return of a local variable. In that case, we wouldn't need copy or move constructors; the poo
instance would be created and passed to the fn by reference ("under the hood").
Note that in C++17 you can use guaranteed copy elision (RVO) to get around this:
poo(std::string s) : _s(std::move(s)){}
poo operator +(const poo &a) const {
return poo(_s + a._s);
}
Demo
However, even in C++20, named return value optimization is not yet guaranteed. An implementation is permitted to use a move operation instead.
[class.copy.elision] states:
In the following copy-initialization contexts, a move operation might be used instead of a copy operation:
- If the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With