1. ホーム
  2. c++

[解決済み] std::vector::erase() および std::deque::erase() におけるコピー/ムーブ代入について

2022-06-20 20:23:56

疑問点

回答中 別の質問 に対する微妙に異なる表現に出くわしました。 std::vector::erase()std::deque::erase() .

C++14 では、次のように記述されています。 std::deque::erase ( [deque.modifiers]/4-6 , emphasis mine)。

効果 ...

複雑さ。 デストラクタの呼び出し回数は、消去される要素の数と同じですが の呼び出し回数は、消去された要素の数と同じです。 代入演算子 の呼び出し回数は、消去された要素の数より少ない数である。 消去された要素の前と、消去された要素の後の要素の数のうち、少ない方の数以下であること。

投げます。 のコピーコンストラクタ、移動コンストラクタ、代入演算子、移動代入演算子で例外がスローされない限り、何も起こりません。 T .

そして、以下がその内容です。 std::vector::erase ( [vector.modifiers]/3-5 ):

エフェクト。 ...

複雑さ。 のデストラクタは T は、消去された要素の数と同じ回数だけ呼び出されますが 移動代入演算子 T は、消去された要素の後のベクトルの要素数に等しい回数だけ呼び出されます。

スローします。 のコピーコンストラクタ、移動コンストラクタ、代入演算子、移動代入演算子で例外がスローされない限り、何も起こりません。 T .

見ての通り、両者の例外指定は同じですが std::vector については、move assignment operator が呼び出されることが明示されています。

の要件もあります。 T であることが必要です。 MoveAssignable のために erase() の両方で動作するように std::vectorstd::deque (表100) が、これは移動代入演算子の存在を意味しません。コピー代入演算子を定義し、移動代入演算子を定義しないことも可能で、このクラスは MoveAssignable .

念のため、GCCとClangで確認したところ、確かに std::vector::erase() は移動代入演算子がなければコピー代入演算子を呼び出しますし std::deque::erase() は同じことをします ( デモ ).

問題は、私が何かを見逃しているのか、それともこれは標準の(編集上の)問題なのか、ということです。

更新しました。 を投稿しました。 LWG issue #2477 .

どのように解決するのですか?

Lenexaミーティングでの問題 を取得しました。 となり、解決案が提示されました。

この文言はN4296に関連しています。

23.3.3.4 [deque.modifiers]/5を次のように変更します。

-5- 複雑さ : デストラクタの呼び出し回数 T は消去された要素の数と同じですが、代入演算子の呼び出しの数である T は、消去された要素の前の要素数と、消去された要素の後の要素数のうち、小さい方の値以下となります。

23.3.6.5 [vector.modifiers]/4を次のように変更します。

-4- 複雑さ : のデストラクタは T は消去された要素の数と同じ回数だけ呼び出されるが、その際 を動かす の代入演算子は T は、消去された要素の後のベクトルの要素数に等しい回数だけ呼び出されます。

つまり、もし解決が受け入れられるなら、移動の割り当てについて特に言及されることはなく std::vector::erase に対する文言は削除され、また std::deque::erase の表現も の表現も少し明確になります。