假设我有一个类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
的指针,并且必须能够确定其大小。
答案 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;
};