如何让一个类总是在复制/移动时重建?

时间:2016-03-12 17:47:37

标签: c++

假设我有一个类A,它包含指向包含它的类的指针及其大小:

struct A
{
    void* parent;
    std::size_t size;
    template<typename T> A(T* p) : parent(p), size(sizeof(T)) { }
};

这在其他类中使用如下:

struct B
{
    A a { this };
};

到目前为止,这么好。但是复制或移动包含类时会出现问题。永远不会重建A,仍然指向B上一个实例:

B b1;
B b2 = b1;
assert(b1.a.parent != b2.a.parent); // oops!

显而易见的解决方案是删除A的副本并移动构造函数:

struct A
{
    void* parent;
    std::size_t size;
    template<typename T> A(T* p) : parent(p), size(sizeof(T)) { }
    A(const A&) = delete;
    A(A&&) = delete;
};

...但这会迫使我在使用operator=的任何类中定义自定义复制/移动构造函数和A。 是否有更简单的方法来达到同样的效果?

编辑:我应该提到,A对其父类占用的内存做了一些'脏'技巧。它需要一个指向parent的指针,并且必须能够确定其大小。

3 个答案:

答案 0 :(得分:2)

A的偏移量保存在其所有者的开头。

struct A
{
    std::ptrdiff_t parent_offset;
    template<typename T> A(T* p) : parent_offset(
        reinterpret_cast<std::uintptr_t>(this) -
        reinterpret_cast<std::uintptr_t>(p)
      )
    {}

    void* parent() { 
       return reinterpret_cast<void*>(
                  reinterpret_cast<std::uintptr_t>(this) - parent_offset
         );
    }
};

答案 1 :(得分:1)

使用继承和“奇怪的重复模板模式”是解决此问题的另一种方法:

template<typename T> struct A
{
    T* const ptr;
    const std::size_t size;

    A() : ptr(this), size(sizeof(T)) { }
    A(A&&) : A() { }
    A(const A&) : A() { }
};

struct B: A<B>
{
};

虽然我不确定这是否比@n.m.的解决方案更受欢迎。

答案 2 :(得分:0)

错误的设计:

struct parent;

struct inner {
  void do_something() { 
    do_stuff();
    parent->do_stuff();
    more_stuff();
  }
  parent* p;
};

struct parent {
  void do_something() { inner.do_something(); }
  inner my_inner = inner { this };
}

正确的设计:

struct inner {
  void do_stuff();
  void more_stuff();
}

struct parent {
  void do_something() {
    my_inner.do_stuff();
    do_stuff();
    my_inner.more_stuff();
  }
  inner my_inner;
};