5

クラスのメンバー変数をクラスの存続期間中は一定にしたいが、コンストラクターの間は変更可能にする必要がある場合、const_cast を使用することがあります。例:

struct qqq {
 const vector<foo> my_foo;

  qqq(vector<foo>* other) {
    vector<foo>& mutable_foo = const_cast<vector<foo>&>(my_foo)
    other->swap(mutable_foo);
  }
};

コンストラクターでこれを行うことは、この時点で他の誰もそれに依存していないため、最適化などとひどく相互作用しないため、基本的には問題ないと思いました。

しかし最近、これは「未定義の動作」であり、どのような状況下でも構築された後に const オブジェクトを変更することは基本的に違法であると誰かが私に言いました。

誰かが明確にすることができますか?これは悪い/未定義の動作/すべきことですか?

4

2 に答える 2

7

未定義の動作です。C++11 標準のパラグラフ 7.1.6.1/4 によると:

宣言されたクラス メンバー (7.1.1) を変更できることを除いて、 オブジェクトの有効期間中 (3.8) にオブジェクトmutableを変更しようとすると、未定義の動作が発生します。const

この場合、構築後にオブジェクトを「一定にする」必要があるようです。これは不可能です。

vectorが意図されている場合constは、コンストラクターの初期化リストで初期化する必要があります。

qqq(vector<foo>& other) 
    : my_foo(std::move(other)) 
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
}

ポインターによる受け渡しに正当な理由がない限り (その場合は、ポインターが null でないかどうかも確認する必要があります)、一般的な方法である (上記のように) 参照による受け渡しを検討する必要があることに注意してください。

アップデート:

Pete Becker がコメントで正しく指摘しているように、適切な設計では、引数から移動する決定は、コンストラクター自体ではなく、 のコンストラクターの呼び出し元vector属する必要があることが示唆されます。qqq

コンストラクターが常にその引数から移動することになっている場合は、コンストラクター自体が呼び出し元に何を期待しているかを明確にして、rvalue 参照を受け入れさせることができます。

qqq(vector<foo>&& other) 
//             ^^
    : my_foo(std::move(other)) 
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
}

このように、呼び出し元はのコンストラクターへの入力で右辺値を提供する必要があります。qqq

std::vector<foo> v;
// ...
qqq q1(v); // ERROR!
qqq q2(std::move(v)); // OK! Now the client is aware that v must be moved from
于 2013-04-18T17:43:33.750 に答える