Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

operator + need Move Constructors

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

like image 601
joseAndresGomezTovar Avatar asked Jul 23 '19 15:07

joseAndresGomezTovar


People also ask

Why do we need move constructors?

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.

Which operator is used with constructor?

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.

What is move constructor and assignment operator?

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.

What is a move operator in C++?

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.


1 Answers

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

like image 170
AndyG Avatar answered Sep 20 '22 18:09

AndyG