1

VC10 (Visual Studio 2010) での unordered_set/map の移動コンストラクターは、呼び出された後に右側を未定義の状態にし、他の操作 (「挿入」など) が惨めに失敗するようです。移動代入演算子はうまく機能しているようです。ただし、法線セット/マップはすべての場合で正しく動作するようです。さらに、VC11 (Visual Studio 2012) ではすべて正常に動作しているようです。

これは VC10 での _Hash 実装のバグですか、それとも何か不足していますか? ご意見をお寄せいただきありがとうございます。

#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>

std::set<int> si0;
std::unordered_set<int> usi0;

std::map<int, int> mii0;
std::unordered_map<int, int> umii0;

int _tmain(int argc, _TCHAR* argv[])
{
    si0.insert(0);
    si0.insert(1);
    si0.insert(2);
    std::set<int> si( std::move(si0) ); // fine!
    si0.insert(666);

    usi0.insert(0);
    usi0.insert(1);
    usi0.insert(2);
    //std::unordered_set<int> usi( std::move(usi0) ); // this seems to put usi0 to an undefined state, which makes 'insert' below cry!
    std::unordered_set<int> usi; usi = std::move(usi0); // this works!
    usi0.insert(666);

    mii0[0] = 0;
    mii0[1] = 1;
    mii0[2] = 2;
    std::map<int, int> mii( std::move(mii0) ); // fine!
    mii0[666] = 666;

    umii0[0] = 0;
    umii0[1] = 1;
    umii0[2] = 2;
    //std::unordered_map<int, int> umii( std::move(umii0) ); // this seems to put umii0 to an undefined state, which makes 'insert' below cry!
    std::unordered_map<int, int> umii; umii = std::move(umii0); // this works!
    umii0[666] = 666;

    return 0;
}
4

1 に答える 1

1

さて、VC10 での _Hash クラスの実装をさらに掘り下げて VC11 の実装と比較したところ、VC10 での _Hash クラスのムーブ コンストラクターがその '_Max_bucket_size' メンバーを初期化せず、ロジックがこの初期化されていない値を右側 (移動された _Hash インスタンス) を削除し、右側を初期化されていない状態のままにします。

これは、移動コンストラクターの右側が実際に一時的なオブジェクトである場合は問題ありませんが、私のロジックは右側のオブジェクトを "リセット" するために移動コンストラクターに依存しており、右側のオブジェクトはその後再構築されます。

移動割り当てバージョンは、左側のオブジェクトを何らかの形で適切に構築する必要があるという点で機能します (この場合、'_Max_bucket_size' が適切に初期化された状態でデフォルトで構築されます)。右側にスワップすると、右側はそうではありません。悪い状態のまま。それにもかかわらず、左側からスワップされた状態を取得して右側を残すことは、純粋なスワップ以上のことを行う右側をリセットする必要があるムーブ代入演算子の標準的な動作に準拠しません!

VC11 での対応する実装では、動作が修正され、標準に準拠しているようです。

于 2012-10-08T19:06:58.747 に答える