3

我有一个类应该包含对某些数据的引用,而不拥有该数据(即保证实际数据不会超出范围)。特别是,该类不能复制——数据大小很容易达到几 GB。

现在,通常的实现(我假设)是引用数据:

struct holder_ref {
    type const& value;

    holder_ref(type const& value) : value(value) { }
};

(请注意,constness 与问题完全无关)。

现在,我绝对需要这个类是可分配的(即有一个工作的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,我需要一个符合标准的解决方案。)

4

3 回答 3

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;
};

只要您始终从引用中分配给指针,您就知道您有一个有效的对象(或者您之前以“空引用”结束,在这种情况下您还有其他更大的问题,因为您已经调用了未定义的行为)。

使用这个解决方案,接口完全根据引用来实现,但在底层使用了一个指针,以便类型是可分配的。在接口中使用引用确保没有使用指针带来的问题(即,您永远不必担心指针是否为空)。

编辑:我已经更新了示例以允许持有人默认可构造。

于 2010-07-19T20:26:28.513 回答
3

我会使用指针支架。但是,如果您对此坚决反对,那么如何隐藏您的展示位置 new operator=

holder_ref& operator =(holder_ref const& other) {
    new (this) holder_ref(other);
    return *this;
}
于 2010-07-19T20:26:40.113 回答
1

是否足够符合 TR1 weak_ptr 标准?

于 2010-07-19T20:24:17.730 回答