3

そのデータを所有せずに、いくつかのデータへの参照を保持する必要があるクラスがあります (つまり、実際のデータはスコープ外に出ないことが保証されています)。特に、クラスはコピーを作成できません。データのサイズは簡単に数ギガバイトになります。

さて、通常の実装(私が推測する)は、データへの参照を持つことです:

struct holder_ref {
    type const& value;

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

const(問題には全く関係ありませんのでご注意ください)。

今、私は絶対にこのクラスを割り当て可能にする必要があります (つまり、作業中の を持っていoperator =ます)。これはかなり一般的な問題だと思っていましたが、以前にどのように解決したかを思い出せません。

問題は、参照を割り当てることができず、これを回避する方法がないことです。私が思いついた唯一の解決策は、代入演算子の代わりに配置 new を使用することです。

// x = other_x; gets replaced with:
x.~T();
new (&x) T(other_x);

現在、これは機能し、標準に準拠しています。しかし、それは確かに醜いです。いいえ - 受け入れられません。

だから私は代替案を探しています。1 つのアイデアはポインターを使用することですが、コンストラクターが実際に動作することが保証されているかどうかはわかりません (また、従わなければならないインターフェイスのために、ポインターを渡すことは不可能です)。

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

常に参照からポインターに割り当てている限り、有効なオブジェクトがあることがわかります (それ、または以前に「null 参照」になってしまった場合、他の大きな問題が発生します。未定義の動作を呼び出しました)。

このソリューションでは、インターフェイスは完全に参照の観点から実装されますが、内部ではポインターが使用されるため、型が割り当て可能になります。インターフェイスで参照を使用すると、ポインターの使用に伴う懸念がなくなります (つまり、ポインターが null であるかどうかを心配する必要はありません)。

編集:ホルダーがデフォルトで構築可能になるように例を更新しました。

于 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 に答える