我有一个包含数据成员的类,它跟踪外部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
,所以实际上我只需需要移动操作。到目前为止,我所想到的一切都是半生不熟的。
答案 0 :(得分:2)
您可以创建一个新类来处理所有权更改。将现有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将与你发布的内容保持不变,除了重命名)。
答案 1 :(得分:1)
首先是一个有点危险的解决方案:
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时(因为您无法将指针转换为成员到虚拟基类)。
这种情况需要手动更新每个成员,现在我找不到任何自动解决方案。