2013-03-29 17 views
5

Poniższe awarii programu z winy segmention:winy segmentacji podczas przemieszczania std :: vector

#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; 
} 

Kod jest skompilowane z g ++ w wersji 4.7.2 (Debian 4.7.2-5):

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

Co robię źle? Problem wydaje się być w konstruktorze ruchu std :: vector, ponieważ wszystko działa bez niego. Wygląda na to, że obiekt danych z randomizacji() jest niszczony, gdy funkcja się kończy, ale czy nie powinna raczej zostać przeniesiona do obiektu danych w głównej kolejności?

+3

Należy zwrócić uwagę, że tutaj nie ma potrzeby zwracania wartości * rvalue * (nawet jeśli ważne jest, aby zwrócić odwołanie do lokalnej zmiennej automatycznej). Wartości zwracane przez funkcję są zawsze przenoszone, jeśli to możliwe. –

Odpowiedz

13

Funkcja:

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

Zwraca odwołanie do lokalnego obiektu, który ma być zniszczony po przywróceniu połączenia. Dlatego Twój program ma Niezdefiniowane zachowanie. W związku z tym powrócił odniesienia będzie zwisające przez czas konstruktor akcja data jest wywołany tutaj:

data d = randomize(); 

Należy zwrócić wartość typu data, i nie należy wyraźnie powołać std::move():

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

w ten sposób można również dać kompilator możliwość wykonywanej (Named) Return Value Optimization, co może prowadzić w żadnym wywołaniu konstruktora ruchu w ogóle.

+0

Dzięki za odpowiedź! Ale czy ta optymalizacja będzie zawsze wykonywana przez gcc, czy są pewne wyjątki? –

+0

@PavelDavydov: Nie ma za co. To zależy wyłącznie od kompilatora i nigdy nie powinieneś polegać na założeniu, że ta elizacja jest lub nie jest wykonywana. Po prostu nie możesz powiedzieć. W tym przypadku jednak stanie się tak, że przy wystarczająco wysokim poziomie optymalizacji każdy kompilator powinien odwołać się do konstruktora ruchu. Ale znowu nie jest to coś, na czym powinieneś polegać. –

0

myślę, że to będzie działać i nie będzie zależeć na optymalizacje kompilatora:

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

wartość Zwrot musi być wykonana przed zniszczeniem zmiennej lokalnej d.