数据成员跟踪在复制时拥有类的"this"

data member tracking owning class's `this` across when copied

本文关键字:拥有 this 跟踪 复制 数据成员      更新时间:2023-10-16

我有一个类,其数据成员跟踪外部this作为其所有者。我想做的是在复制构建后跟踪新的owner

class MyType;
struct Member {
  MyType* owner;
  Member(MyType* m) : owner{m} {} // store pointer to owner
};
struct MyType {
    Member mem;
    MyType() : mem(this) { } // I am my member's owner
};
int main() {
  MyType a;
  MyType b(a);
  assert(b.mem.owner == &b); // fail.
}
当然,我可以编写MyType(const MyType&);构造函数并设置新指针,但真正的类是巨大的,编写构造函数将引入维护问题。如果我可以约束它(甚至引入另一个中间类/包装器),我会更高兴。

实际情况是一个unique_ptr成员,它有一个Deleter,引用了拥有的this,所以实际上我只需要移动操作。到目前为止,我所想到的一切都很不成熟。

您可以创建一个新类来处理所有权更改。将您现有的MyType重命名为MyTypeImpl(成员不变),并由此派生创建一个新的MyType:

struct Member {
    MyType* owner;
    Member(MyType* m) : owner{m} {} // store pointer to owner
};
struct MyTypeImpl {
    Member mem;
protected:
    // protected constructor to disallow creating instances of this class
    MyTypeImpl(MyType *pThis) : mem(pThis) { } // I am my member's owner
};
struct MyType: public MyTypeImpl {
    MyType(): MyTypeImpl(this) { }
    MyType(const MyType &r): MyTypeImpl(r) { mem.owner = this; }
    MyType(MyType &&r): MyTypeImpl(std::forward(r)) { mem.owner = this; }
    // etc
};

一个变化将是成员指向MyTypeImpl而不是MyType(那么MyTypeImpl将与你发布的内容保持不变,除了重命名)。

第一个有点危险的解决方案:

class MyType;
struct Member {
  std::ptrdiff_t ownerOffset;
  Member(MyType* m, Member MyType::* p) : 
    ownerOffset{ reinterpret_cast<char*>(m) 
    - reinterpret_cast<char*>(this) } // store offset to owner
  { assert( &(m->*p) == this ); } // make sure it is our owner
  MyType* getOwner() {        
    return reinterpret_cast<MyType*>(
      reinterpret_cast<char*>(this) + ownerOffset);
  }
};
struct MyType {
    int x; //some offset
    Member mem;
    MyType() : mem(this, &MyType::mem) { } // I am my member's owner
};
int main() {
  MyType a;
  MyType b(a); 
  assert(b.mem.getOwner() == &b); // ok.
}

但是这对于一些外来类不起作用,比如当你虚继承MyType时(因为你不能将成员指针强制转换为虚基类)。
这种情况需要手动更新每个成员,目前我找不到任何自动解决方案。