2013-03-29 6 views
5

segmention障害と次のプログラムがクラッシュ:セグメンテーション障害STDを移動::ベクトル

#include <iostream> 
#include <vector> 

using namespace std; 

struct data 
{ 
    data() : a(random()), b(random()), v({random(), random(), random()}) {} 
    data(data&& m) noexcept : a(m.a), b(m.b), v(std::move(m.v)) { } 

    long int a; 
    long int b; 
    std::vector<long int> v; 
}; 

data&& randomize() 
{ 
    srandom(time(0)); 
    data d; 
    d.a = random(); 
    return std::move(d); 
} 

int main(int argc, char** argv) 
{ 
    data d = randomize(); 
    cout << d.a << " " << d.b << endl; 
    return 0; 
} 

コードをg ++バージョン4.7.2(Debianの4.7.2-5)でコンパイルされている:

g++ -std=c++11 -g test.cpp 

私は何が間違っていますか?問題は、std :: vector moveコンストラクタにあるようで、すべてがうまく動作しません。関数が終了するとrandomize()のデータオブジェクトが破棄されるように見えますが、メインオブジェクトのデータオブジェクトに移動するのではなく、

+3

ここで* rvalue *参照を返す必要はありません(ローカル自動変数への参照を返すことが有効であっても)。可能な場合、関数戻り値は常に移動されます。 –

答えて

13

この機能:

data&& randomize() 
{ 
    // ... 
    data d 
    // ... 
    return std::move(d); 
} 

、コールから戻ると破壊されようとしているローカルオブジェクトへの参照を返します。したがって、プログラムには未定義の動作があります。そのため、返された参照はdataの移動コンストラクタがここで呼び出された時点でぶら下がり次のようになります。

data d = randomize(); 

あなたがタイプdataを返す必要がありますし、あなたが明示的にstd::move()呼び出すべきではありません。

data randomize() 
{ 
    // ... 
    data d 
    // ... 
    return d; 
} 

このようにして、(Named) Return Value Optimizationを実行する機会をコンパイラに与えて、ムーブコンストラクタをまったく呼び出さないようにすることもできます。

+0

あなたの答えをありがとう!しかし、この最適化は常にgccによって実行されるか、あるいはいくつかの例外がありますか? –

+0

@PavelDavydov:あなたは歓迎です:)これはコンパイラが決めるべきことです。この溶出が実行されているかどうかという仮定に頼るべきではありません。あなたは伝えることができません。しかし、この場合、十分に高い最適化レベルを設定すると、どのコンパイラも移動コンストラクタへの呼び出しを削除する必要があります。しかし、これもまたあなたが頼りにするべきことではありません。 –

0

私はこれが動作すると、コンパイラの最適化に依存しないだろうと思う:

data randomize() 
{ 
    // ... 
    data d 
    // ... 
    return std::move(d); 
} 

戻り値はローカル変数dの破壊前に構築する必要があります。

関連する問題