1

I have the following class :

class Component {
  public:
    // Constructor
    explicit Component(const void* data, size_t size)
      : _size(size),
        _data(new int[_size]) {
          (void)memcpy(_data, data, _size);
    }

    // Destructor
    ~Component() {
      delete[] _data;
    }

    // Copy-ctor.
    Component(const Component& o)
      : _size(o._size),
        _data(new uint8_t[_size]) {
     (void)memcpy(_data, o._data, _size);
   }

   // Assignment operator
   Component& operator=(const Component& o) {
     if (this != &o) {
       delete[] _data;
       _size = o.getSize();
       _data = new uint8_t[_size];
       (void)memcpy(_data, o.getData(), _size);
     }
     return *this;
   }

   // Move-constructor
   Component(Component&& o)
     : _size(o._size),
       _data(o._data) {
     o._data = nullptr;
   }

   // Move assignment
   Component& operator=(Component&& o) {
     if (this != &o) {
       delete[] _data;
       _size = o._size;
       _data = o._data;
       o._data = nullptr;
     }
     return *this;
   }

   private:
    size_t _size;
    int _data;
};

I would like to test my move-constructor. So I tried to do :

void f(Component&& c) {
  Component c2 = c; // Expect to use move-constructor
}
int data[] = { 0, 1 };
Component c{&data[0], sizeof(data)};
f(std::move(c)); // getting a rvalue reference from lvalue reference

But then I saw that it was my copy-constructor that was called and not the move-constructor. Do you have any idea why ?

Praetorian
  • 106,671
  • 19
  • 240
  • 328
klaus
  • 754
  • 8
  • 28

2 Answers2

3

In this code

void f(Component&& c)
{
    Component c2 = c; // Expect to use move-constructor
}

c is an lvalue. That's what lets you use it more than one time inside of f.

The && parameter is an indication that the caller will not need the object any longer and you are free to loot it. But now your function is conceptually the owner... subroutines that you call should not loot your object unless you give them permission in turn.

Making c an rvalue would break many usecases, for example:

void f(string&& s)
{
    string inputfilename = s + ".in";
    string outputfilename = s + ".out";
    // use s in some other ways
}

To give subroutines permission to loot your parameter, you use std::move.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • @klaus: No... it accepts an rvalue (prvalue or xvalue), but it is an lvalue.... up until the return statement, when all by-value and rvalue-reference parameters and locals become xvalues. – Ben Voigt Jan 12 '18 at 16:12
  • can you give link to c++ standard discussing above topic , i'd like to read more – emaditaj Dec 04 '20 at 00:10
  • 1
    @emaditaj: That would be https://eel.is/c++draft/basic.lval it is pretty long and complicated. The first example (actually a block of code containing multiple examples) ends with `A&& ar = static_cast(a);` and the note, `ar` is an lvalue. – Ben Voigt Dec 04 '20 at 22:06
1

It looks like you need to change f to

void f(Component&& c) {
    Component c2 = std::move(c);
}

And call it like:

f(c);

Please see: similar example

NOTE: I haven't tested it, but please see answers to the other thread for an explanation.