2013-08-10 13 views
10

Zrobiłem szukać w Internecie i znalazłem 3 sposoby definiowania konstruktora ruch:Jak poprawnie zdefiniować konstruktor ruchu?

  1. powołując się na kompilatora:

    T(T&& other) = default; 
    
  2. dereference this wskaźnik:

    T(T&& other) { 
        *this = std::move(other); 
    } 
    
  3. Jawnie przeniesieniu wszyscy członkowie:

    T(T&& other) { 
        T.a = other.a; 
        T.b = other.b; 
        //... 
    } 
    

Która z nich jest właściwa? (I jest drugi nawet prawidłowa?)

+3

Drugi nie jest poprawny (nie można ogólnie odwołać się do obiektu, który nie istnieje), trzeci jest głupi. –

+0

@KerrekSB Znalazłem drugi z witryny MSDN: http://msdn.microsoft.com/en-us/library/dd293665.aspx może MSVC obsługuje go .. nie wiem o GCC – texasbruce

+0

znalazłem trzeci z tej strony też ... – texasbruce

Odpowiedz

15

Właściwym sposobem generyczny jest przeniesienie-skonstruować każdy członek, ale to właśnie wersja defauted robi i tak:

T(T && rhs) 
: a(std::move(rhs.a)) 
, b(std::move(rhs.b)) 
{ } 

Jako szorstkiej reguły, należy użyć definicja domyślnej jeśli to wszystko, czego potrzebujesz, i trzeba napisać ex ­ PLI ­ cit ruch konstruktora jeśli robisz coś, co ex ­ pli ­ citly narzędzia przenieść semantykę, takich jak menedżer zasobów unikalnych własności:

URM(URM && rhs) 
: resource(rhs.resource) 
{ 
    rhs.resource = nullptr; 
} 

Wskaźnikiem tego, czy jest to odpowiednie, jest prawdopodobnie to, czy klasa ma zdefiniowany przez użytkownika de ­ struc ­ tor. W tym przykładzie destruktor zwolni zarządzany zasób, a to musi się zdarzyć tylko raz, więc obiekt przeniesiony z musi zostać zmodyfikowany.


To nie ma związku, ale ponieważ jesteś wspomnieć operator przypisania, oto popularny swap i przypisywania/Zmienne idiom:

void swap(URM & rhs) noexcept  // assume members are noexcept-swappable! 
{ 
    using std::swap; 
    swap(resource, rhs.resource); 
    // ... 
} 

URM & operator=(URM rhs) noexcept // pass by value 
{ 
    rhs.swap(*this); 
    return *this; 
} 

Piękno tego podejścia jest to, że wystarczy tylko jeden pojedyncza wersja operatora przypisania, która działa zarówno w przypadku plików tymczasowych, jak i tymczasowych, przy użyciu konstrukcji ruchu, o ile jest to właściwe, i dopóki wszyscy członkowie są dobrze zaprojektowani, potrzebna jest również tylko jedna funkcja swap. Co więcej, jeśli funkcja wymiany nie wyrzuci (na co powinna zezwolić dobrze zaprojektowana klasa), to operator przydziału nie rzuca, ponieważ wszystkie możliwe wyjątki wystąpiłyby już na stronie wywołania.

+0

Czy ostatni jest naprawdę potrzebny, jeśli na przykład 'resource' jest' std :: unique_ptr'? –

+3

@JoachimPileborg: Nie. Przykład może być * implementacją * słowa 'unique_ptr'. –

+0

Co z domyślnym? Czy mogę w ogóle bezpiecznie z niego korzystać? – texasbruce

1
T(T&& other) 
: data(0) // initialize members 
{ 
    swap(other); // where the class has a member function swap or std::swap(this->data, other.data) 
} 
Powiązane problemy