2011-04-14

ムーブ後のオブジェクトの状態について

n3264: Moved-from state

n3264を理解出来ない人がいるようなので解説。n3264では、ふたつの異なる種類の型のオブジェクトに対する、ムーブ後の保証を規定している。標準ライブラリで定義されている型と、標準ライブラリに渡されるユーザー定義の型である。

ムーブ後のオブジェクトの状態がどうなるかということは、興味深い問題である。根本的には、プログラマーの好きにすればよい。しかし、標準ライブラリと、標準ライブラリに渡される型においては、挙動を決めて置かなければならない。さもなければ、信頼できるコードが書けない。そのため、n3264で、ムーブされた後のオブジェクトの状態が定められた。

17.3.24 [defns.valid.unspecified]には、標準ライブラリで定義されている型のオブジェクトが満たすべき保証が示されている。

標準ライブラリで定義されている型のオブジェクトは、別に明記されていない限り、妥当だが未規定の状態になる。

これは、破棄や代入などの操作が、通常通り行えるということを意味する。ただし、未規定の状態ということに注意する必要がある。たとえば、ムーブ後のstd::vectorのオブジェクトのsize()などがどのような値を返すかは分からないということである。

int main()
{
    std::vector<int> v = { 1, 2, 3 } ;
    std::vector<int> m = std::move(v) ;
    v.size() ; // 未規定
}

Table 34と36で規定されているのは、ユーザー定義の型が、MoveConstructibleやMoveAssignableを満たす際に必要な条件である。これは、17.3.24 [defns.valid.unspecified]とは別ものである。この2つの要求を満たす際の保証ということになる。標準ライブラリで定義されている型の保証より、かなりゆるい。

こちらの保証の意味は、ムーブ後もライブラリが要求する他の保証を満たすこと、というものである。例えば、ある標準ライブラリが、MoveConstructibleかつDestructableを要求した場合、ムーブ後のオブジェクトは、破棄可能でなければならない。もし、CopyAssignableも同時に要求していたのならば、ムーブ後のオブジェクトは代入可能でなければならない。

標準ライブラリで定義されている型は、強い保証を求められる。一方、ユーザー定義の型は、最低限の保証を求められる。

No comments: