我应该如何在菱形模式中调用父移动构造函数?

时间:2017-11-05 08:51:38

标签: c++ c++11 constructor move-semantics diamond-problem

考虑遵循菱形多重继承:

class base;
class d1 : virtual public base;
class d2 : virtual public base
class d3 : public d1, public d2;

base是一个仅移动的类(具有大的仅移动缓冲区)。 d1d2d3也是如此。移动d1d2的构造函数调用base的构造函数。

然后应该做什么移动d3的构造函数?调用d1和d2的移动控制器会导致崩溃(因为base的移动构造函数被调用两次。

这里我有一个最小的可编辑问题实例:

#include <iostream>

struct moveonly {
    moveonly(): data(nullptr) {}
    moveonly(const moveonly &) = delete;
    moveonly(moveonly &&other) {
        this->data = other.data;
        other.data = nullptr;
    }
    ~moveonly() {
        if(data)
            delete[] data;
    }
    char *data;
};

class base {
    public:
        base() = default;
        base(const base &) = delete;
        base(base &&other) : d(std::move(other.d)) {  }
        virtual ~base() = default;
        int a;
        int b;
        moveonly d;
};

class d1 : virtual public base {
    public:
        d1() = default;
        d1(const base &) = delete;
        d1(d1 &&other) : base(std::move(other)) {  }
        int x;
        int y;
};

class d2 : virtual public base {
    public:
        d2() = default;
        d2(const base &) = delete;
        d2(d2 &&other) : base(std::move(other)) {  }
        int r;
        int s;
};

class d3 : public d1, public d2 {
    public:
        d3() = default;
        d3(const base &) = delete;
        // What should I do here?
        d3(d3 &&other) : d1(std::move(other)), d2(std::move(other)) {  }
        int p;
        int q;
};

int main()
{
    d3 child;
    child.d.data = new char[1024];
    for(size_t i = 0; i < 1024; ++i)
        child.d.data[i] = i * 2;
    d3 other_child = std::move(child);
    for(size_t i = 0; i < 1024; ++i) {
        std::cerr << other_child.d.data[i] << ' ';
    }
    std::cerr << std::endl;
    return 0;
}

2 个答案:

答案 0 :(得分:7)

与所有虚拟继承一样,虚拟基础由派生最多的对象初始化,因此:

d3(d3 &&other)
    : base(std::move(other)),   // <== *you* initialize the base
      d1(std::move(other)),
      d2(std::move(other)) {}

答案 1 :(得分:-1)

要求编译器提供实现有什么问题?

d3(d3&amp;&amp;)=默认值; //我认为这是最好的方法,因为它更少错误。

如果您真的想要,可以写出来:

d3(d3&amp;&amp; other):base(std :: move(other)),d1(std :: move(other)),d2(std :: move(other)) {

}