2013-03-29 63 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; 
} 

的代碼被編譯以克++版本4.7.2(Debian的4.7.2-5):

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

我做錯了什麼?這個問題似乎是在std :: vector移動構造函數,導致一切正常工作沒有它。看起來來自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:不客氣:)完全取決於編譯器來決定,而且你不應該依賴這個elision是否被執行的假設。你無法分辨。但是,在這種情況下,會發生什麼情況是,如果具有足夠高的優化級別,則任何編譯器都應該調用移動構造函數。但是,這絕不是你應該依賴的東西。 –

0

我認爲這會工作,並不會依賴於編譯器優化:

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

則返回值的局部變量d的破壞之前建造。