1

so i have a class with deleted copy ctor/assignment, no default ctor, and has move ctor/assignment:

class A {
  int data_ = 0;

public:
    A(const A& other) = delete;
    A& operator=(const A& other) = delete;

    A(int data) : data_(data) {}
    ~A() {}

    A(A&& other) { *this = std::move(other); }
    A& operator=(A&& other) {
        if (this != &other) {
            data_ = other.data_;
            other.data_ = 0;
        }
        return *this;
    }
};

and i have a class B (also no default ctor) that contains A:

class B {
    A a;

public:
    B(const B& other) = delete;
    B& operator=(const B& other) = delete;

    B(int data) : a(data) {}
    ~B() {}

    B(B&& other) { *this = std::move(other); }
    B& operator=(B&& other) {
        if (this != &other) {
            a = std::move(other.a);
        }
        return *this;
    }
};

now the problem is the B move ctor wont compile, because he says theres no default constructor for A, and this is really annoying, i dont want him to create a new A instance when i call the move ctor on B, i want it to move it!

so theres 2 things i could do:

B(B&& other) : a(std::move(other.a)) { *this = std::move(other); }

this wont work, because in the move assignment he will try to move A again.. also if "this == &other == true" he will have moved A from himself making A garbage now..

another way:

make a default private A ctor. make B friend of A. but that sounds so hacky and ugly.. what is the best way to deal with this situation? i really want to avoid having to make a default constructor for A.

thanks in advance.

NetVipeC
  • 4,402
  • 1
  • 17
  • 19
sap
  • 1,188
  • 1
  • 14
  • 25
  • 1
    Do not write a custom move ctor, use the default one. – n. m. could be an AI Aug 06 '14 at 15:43
  • 2
    You shouldn't be doing `*this = std::move(other);` at all in copy constructors. – juanchopanza Aug 06 '14 at 15:43
  • @n.m. I thought the same, but they want to set the `int` data member to `0`. – juanchopanza Aug 06 '14 at 15:44
  • n.m: i need a default move because the destructor checks: if(data_) deletesomething(); data isnt actually an int, its a resource. juanchopanza: why not? the advice is from microsoft itself: "If you provide both a move constructor and a move assignment operator for your class, you can eliminate redundant code by writing the move constructor to call the move assignment operator." source: http://msdn.microsoft.com/en-us/library/dd293665.aspx – sap Aug 06 '14 at 15:45
  • 2
    @sap I'm with [Hinnant on this one](http://stackoverflow.com/questions/17118256/implementing-move-constructor-by-calling-move-assignment-operator). – juanchopanza Aug 06 '14 at 15:51
  • @juanchopanza thanks for the link, interesting stuff. so i guess the ideal would be to manually write both the move and assign? the by-value option in that thread is not possible though, because i really need these objects to be non-copiable but always movable. just like an unique_ptr i guess. – sap Aug 06 '14 at 15:57

2 Answers2

1

The solution would be to do this:

class A {
  int data_ = 0;

public:
    A(const A& other) = delete;
    A& operator=(const A& other) = delete;

    A(int data) : data_(data) {}
    ~A() {}

    A(A&& other) : data_(other.data_) { other.data_ = 0; }
    A& operator=(A&& other) {
        if (this != &other) {
            data_ = other.data_;
            other.data_ = 0;
        }
        return *this;
    }
};

class B {
    A a;

public:
    B(const B& other) = delete;
    B& operator=(const B& other) = delete;

    B(int data) : a(data) {}
    ~B() {}

    B(B&& other) : a(std::move(a)) {  }
    B& operator=(B&& other) {
        if (this != &other) {
            a = std::move(other.a);
        }
        return *this;
    }
};

Although, since A only contains an int in it, it would not result in better performance than a copy...

Mr.WorshipMe
  • 713
  • 4
  • 16
  • thanks, thats what i end up doing, im doing this not because of performance, but because i want to be able to move the resource around and not copy it. it makes more sense if i show that in the destructor of all those classes theres something like: if(id_) delete resource_; that way i can still use them in containers (by moving) while preventing copying and multiple resource deletion every time a copy reaches the destructor. – sap Aug 07 '14 at 17:55
0

Since you have an Object of A declared in your class B, you need to create it when you construct B. A normal Object in C++ can't have no value and it could not be created (cause there is no default constructor).

To fix your problem, make a pointer to a that can have the value 0, so it needn't to be created in your constructor. Change this line:

A a;

into this:

private:
    A *a = 0;
msrd0
  • 7,816
  • 9
  • 47
  • 82