12

以下のコードのstd::move()は、Visual Studio 2013 (デバッグ構成あり) でコンパイルすると実行時警告を発行しdestますnullptr。ただし、ソース範囲は空であるため、dest決してアクセスしないでください。C++ 標準は、これが許可されるべきかどうかについて不明確である可能性がありますか? それは次 のように述べています。 Anullptrはその要件を満たしているようです。

#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec;
    int* dest = nullptr;
    // The range [begin(vec),end(vec)) is empty, so dest should never be accessed.
    // However, it results in an assertion warning in VS2013.
    std::move(std::begin(vec), std::end(vec), dest);
}
4

3 に答える 3

17

Requires:句を満たす必要があるだけでなく、 Effects:およびReturns:句のすべても満たす必要があります。それらを見てみましょう:

効果:範囲内の要素をから開始して までの範囲[first,last)にコピーします。[result,result + (last - first))firstlast

の場合first == last、範囲[result, result + 0)は有効な範囲でなければなりません。

[iterator.requirements.general]/p7 の状態:

範囲[i,i)は空の範囲です。...から到達可能Range [i,j)な場合にのみ有効です。ji

そして、同じセクションのp6には次のように記載されています。

を作る式の適用の有限のシーケンスがある場合にのみ、反復子jは反復子から到達可能であると呼ばれます。i++ii == j

これらの段落から、次のように結論付けます。

int* dest = nullptr;

次に[dest, dest)、有効な空の範囲を形成します。したがって、Effects:段落の最初の文は、私には問題ないように見えます。

負でない整数 ごとn < (last - first)に、 を実行し*(result + n) = *(first + n)ます。

負でない整数は存在n < 0しないため、代入は実行できません。したがって、2 番目の文は を禁止していませんdest == nullptr

戻り値: result + (last - first) .

[expr.add]/p8 では特に、任意のポインター値に 0 を加算することができ、結果は元のポインター値と等しくなります。したがってdest + 0、 は に等しい有効な式ですnullptrReturns:句に問題はありません。

Requires: result範囲内であってはなりません[first,last)

dest空の範囲の「内」にあると解釈する合理的な方法はありません。

複雑さ:まさにlast - first代入。

これにより、割り当てを実行できないことが確認されます。

この例を整形式以外のものにするステートメントは、標準にはありません。

于 2013-10-20T21:55:41.703 に答える
-1

Visual Studio での STL のデバッグ ビルドは、追加のパラメーター検証を行います。この場合、 dest が null であってはならないため、 null ではないことを検証していますが、これは失敗しています。リリース ビルドは期待どおりに機能する可能性があり、dest を使用することはありませんが、入力データが有効になりません。

STL のデバッグ ビルドは、「あなたの入力が間違っています」と言ってあなたを助けようとしています。状況によっては不適切な入力が問題にならない場合もありますが、バリデーターは、どのような条件下で不適切なデータが渡されているかを知ることができません。個人的には、実稼働環境でランタイム例外がスローされるよりも、デバッグ ビルドでの不適切な入力について VS に通知してもらいたいと考えています。

確かに、あなたは次のようなことをするかもしれません:

int* dest = nullptr;
if (vec.size() > 0) dest = realDest;
std::move(std::begin(vec), std::end(vec), dest);

しかし、バリデーターはそれを認識していないため、特に修正は非常に簡単で (常に有効な出力イテレーターを渡すだけです)、それについて警告しないと、本番環境での実行時にアプリケーションにひどい結果をもたらす可能性があるため、最悪の事態が想定されます。 .

于 2013-10-20T18:06:57.170 に答える