キャストされたベクターのベクターでの未定義の動作


19

なぜこのコードは初期化されていないように見える初期化されていない整数の数を書き込むのですか?

#include <iostream>
#include <vector>
using namespace std;


int main()
{
    for (int i : vector<vector<int>>{{77, 777, 7777}}[0])
        cout << i << ' ';
}

出力はになるはず77 777 7777です。

このコードは未定義であるべきですか?

回答:


18

vector<vector<int>>{{77, 777, 7777}}一時的なものでありvector<vector<int>>{{77, 777, 7777}}[0]、ranged-forでの使用は未定義の動作になります。

最初に、次のように変数を作成する必要があります

#include <iostream>
#include <vector>
using namespace std;


int main()
{
    auto v = vector<vector<int>>{{77, 777, 7777}};
    for(int i: v[0])
        cout << i << ' ';
}

また、Clang 10.0.0を使用すると、この動作に関する警告が表示されます。

警告:ポインターを支えるオブジェクトは、完全式の最後で破棄されます[-Wdangling-gsl] vector> {{77、777、7777}} [0]


2
この悪い習慣が広がるのを防ぐためにusing std::vector代わりに使用してくださいusing namespace std;
infinitezero

10

これは、繰り返し処理するベクトルがループに入る前に破棄されるためです。

これは通常起こることです:

auto&& range = vector<vector<int>>{{77, 777, 7777}}[0];
auto&& first = std::begin(range);
auto&& last = std::end(range);
for(; first != last; ++first)
{
    int i = *first;
    // the rest of the loop
}

次のように評価されるため、問題は最初の行から始まります。

  1. 最初に、指定された引数を使用してベクトルのベクトルを作成します。名前がないため、そのベクトルは一時的なものになります。

  2. 次に、範囲参照は、それを含むベクトルが有効である限りのみ有効になる添え字付きベクトルにバインドされます。

  3. セミコロンに到達すると、一時的なベクトルが破棄され、そのデストラクタで、添え字付きのベクトルを含む格納されたすべてのベクトルが破棄され、割り当てが解除されます。

  4. あなたは、繰り返される破壊されたベクトルへの参照で終わります。

この問題を回避するには、2つの解決策があります。

  1. ループの前にベクトルを宣言して、ループを含むスコープが終了するまで継続するようにします。

  2. C ++ 20には、これらの問題を解決するために提供されるinitステートメントが付属しており、ループの直後にベクトルを破棄する場合は、最初のアプローチよりも優れています。

    for (vector<vector<int>> vec{{77, 777, 7777}}; int i : vec[0])
    {
    }

これは「通常」発生することではありません。この正確な動作(および適切なスコープと命名に関する考慮事項)は、as-ifルールに従って、標準で義務付けられています。
Konrad Rudolph

私は生涯について言及しています。手作業で同じコードを記述した場合でも、希望する動作が得られ、コンパイラーが最適化を行うことでできることを保証するだけです
dev65

TIL C ++ 20宣言宣言範囲構文。幸せか悲しいかわからない。
翼のある小惑星

6
vector<vector<int>>{{77, 777, 7777}}[0]

これがぶら下がっていると思います。

範囲指定の定義は、結腸のRHSがその期間中「生きている」ことを保証しますが、それでも一時的な添え字を付けています。添え字の結果のみが保持されますが、その結果は参照であり、実際のベクトルは、それが宣言されている完全式を超えて存続することはできません。これはループ全体を表すものではありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.