我有一个类应该保存对某些数据的引用,而不拥有该数据(即保证实际数据不会超出范围)。 特别是,该类无法复制 - 数据容易达到几千兆字节。
现在,通常的实现(我假设)是对数据的引用:
struct holder_ref {
type const& value;
holder_ref(type const& value) : value(value) { }
};
(请注意,const
与问题完全无关。)
现在,我绝对需要这个类可以赋值(即有一个有效的operator =
)。我认为这是一个相当普遍的问题,但我不记得(如果有的话)我之前是如何解决它的。
问题是无法分配引用并且根本无法解决此问题。我提出的唯一解决方案是使用placement new代替赋值运算符:
// x = other_x; gets replaced with:
x.~T();
new (&x) T(other_x);
现在,这可以并且符合标准。但它肯定是丑陋的。不 - 不可接受。
所以我正在寻找其他选择。一个想法是使用指针,但我不确定我的构造函数是否确实可以保证工作(由于我必须遵守的接口,传递指针是不可能的):
struct holder_ptr {
type const* value;
// Is this legal?
holder_ptr(type const& value = 0) : value(&value) { }
};
但是如果可能的话,我宁愿使用引用。只 - 如何实现赋值运算符?
struct holder_ref {
type const& value;
holder_ref(type const& value = 0) : value(value) { }
holder_ref& operator =(holder_ref const& other) {
// Now what?!
return *this;
}
};
作为测试用例,请考虑以下代码:
int main() {
int const TEST1 = 23;
int const TEST2 = 13;
int const TEST3 = 42;
std::vector<holder_ptr> hptr(1);
std::vector<holder_ref> href(2);
// Variant 1. Pointer.
hptr[0] = holder_ptr(TEST1);
// Variant 2. Placement new.
href[0].~holder_ref();
new (&href[0]) holder_ref(TEST2);
// Variant 3. ???
href[1] = holder_ref(TEST3);
assert(*hptr[0].value == TEST1); // Works (?)
assert(href[0].value == TEST2); // Works
assert(href[1].value == TEST3); // BOOM!
}
(另外,为了明确这一点 - 我们所讨论的类型是非POD,我需要一个符合标准的解决方案。)
答案 0 :(得分:6)
我认为使用holder_ptr
没有任何问题。它可以实现如下:
struct bad_holder : std::exception { };
struct holder_ptr {
holder_ptr() : value(0) { }
holder_ptr(type const& value) : value(&value) { }
type const& get() {
if (value == 0) throw bad_holder();
return *value;
}
private:
type const* value;
};
只要你总是从引用中分配指针,你知道你有一个有效的对象(或者你以前最后得到了一个“空引用”),在这种情况下,你有其他更大的问题,因为你'll已经调用了未定义的行为。)
使用此解决方案,接口完全根据引用实现,但在引擎盖下使用指针以便类型可分配。在接口中使用引用可确保使用指针不会产生任何问题(即,您永远不必担心指针是否为空)。
修改:我已更新示例,以允许持有者为默认构造。
答案 1 :(得分:3)
我会使用指针架。但是,如果你已经死定了,那么如何隐藏您的展示位置operator=
:
holder_ref& operator =(holder_ref const& other) {
new (this) holder_ref(other);
return *this;
}
答案 2 :(得分:1)
TR1 weak_ptr标准是否符合要求?