1

Given the class NamedType, I want to call the move-constructor:

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <utility>

template<typename T, typename PARAMETER>
class NamedType {
 public:
  NamedType() { /*std::cout << "default ";*/ }
  NamedType(T const &value) : value_(value) { /*std::cout << "parametrized ";*/ }

  NamedType(NamedType const &other) : value_(other.value_) { std::cout << "copy "; }
  NamedType(NamedType &&other) noexcept : value_(std::exchange(other.value_,0)) { std::cout << "move "; }

  NamedType& operator=(NamedType const &rhs) { value_ = rhs.value_; std::cout << "copyAssign "; return *this; }
  NamedType& operator=(NamedType &&rhs) { value_ = std::exchange(rhs.value_,0); std::cout << "moveAssign "; return *this; }

  ~NamedType() = default;

  T const & Get() const { return value_; }
 private:
  T value_;
};

using Degree = NamedType<int, struct DegreeParameter>;

Degree GetRandom() {
  return Degree{std::rand() % 100};
}

When calling following script

int main() {
  std::srand(std::time(0));
  Degree degreeCopyAssign, degreeMoveAssign;  // no output, since uninitialized
  Degree degreeParametrized(1);  // std::cout << degreeParametrized.Get() << std::endl;

  Degree degreeCopy(degreeParametrized); std::cout << degreeCopy.Get() << std::endl;
  Degree degreeUnknown(GetRandom()); std::cout << degreeUnknown.Get() << std::endl;  // which constructor is called? why no implicit move?
  Degree degreeMove(std::move(GetRandom())); std::cout << degreeMove.Get() << std::endl;

  degreeCopyAssign = degreeCopy; std::cout << degreeCopyAssign.Get() << std::endl;
  degreeMoveAssign = GetRandom(); std::cout << degreeMoveAssign.Get() << std::endl;  // why implicit move here?

  return 0;
}

the move-constructor isn't called, but I expect it to be called for degreeUnknown. Which constructor is called there?

And why is the move-command implicitly called for degreeMoveAssign but not for the move-constructor, cf. degreeMove?

The sample output for the script reads

copy 1
64
move 96
copyAssign 1
moveAssign 7

Thanks :)

Kapa11
  • 311
  • 2
  • 18
  • 6
    [Copy elision](https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization)? – Aconcagua May 06 '19 at 12:52
  • By the way: `Degree degreeCopyAssign; // no output, since uninitialized` is only partially correct; native data types (int, unsigned long, double, etc) are uninitialised; for complex objects, the default constructor is called. However, this one doesn't do anything, thus the `value_` member will remain uninitialised (unless `T` is of class type again...). – Aconcagua May 06 '19 at 12:56
  • @Aconcagua I agree with you. You can paste the code in godbolt and notice that the object is just directly constructed. – user3520616 May 06 '19 at 13:04
  • Off-topic: `rand() % n` gives rather bad distribution. For very simple experiments it might suffice, better prefer C++'s new [random facilities](https://en.cppreference.com/w/cpp/header/random). – Aconcagua May 06 '19 at 13:05
  • @Aconcagua: I thought I ruled this one out. However, turned out that my `GetRandom` function still wasn't complex enough. Indeed, e.g., `Degree GetRandom() { int random_integer = std::rand() % 100; if (random_integer > 75) { Degree degreeLarger75{75}; return degreeLarger75; } else { Degree degreeSmallerEqual75{random_integer}; return degreeSmallerEqual75; } }` gave rise to the move constructor. Thanks for your quick response! – Kapa11 May 06 '19 at 13:17
  • 1
    degreeUnknown is using the parametrized constructor and the copy is elided. degreeMoveAssign is using the move one because the right-hand side is an unnamed temporary. This explanation may be helpful: https://www.internalpointers.com/post/c-rvalue-references-and-move-semantics-beginners – Eljay May 06 '19 at 13:46
  • Per Aconcagua, possible duplicate of [What are copy elision and return value optimization?](https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization) – Davis Herring May 07 '19 at 04:29

0 Answers0