2014-09-09 18 views
5

Wiem, że to pytanie może wydawać się bardzo proste. Ale po prostu nie mogę znaleźć nigdzie przykładu konstruktora ruchu o wskaźnikach no.Przenoszenie Konstruktora bez wskaźników

Mam klasę, która zawiera zmienną obiektu wektorowego. Nie jest to wskaźnik do jednego. Więc moje pytanie: Czy to oznacza, że ​​nie potrzebuję konstruktora ruchu? Czy moja implementacja jest zła i powinienem używać wskaźnika do wektora, a następnie użyć konstruktora ruchu?

Dziękuję

+2

Powinieneś nadal mieć konstruktor ruchu, ponieważ 'std :: vector' może czerpać korzyści z przenoszenia. Wygenerowany przez kompilator (przesunięcie w prawo) powinien być wystarczająco dobry. –

+0

Wierzę, że to się nazywa * Kopiuj Konstruktor *, a nie * Przenieś Konstruktora *. –

+1

@AlexFarber: Domyślny konstruktor kopii jest wystarczająco dobry, jeśli nie ma żadnych wskaźników członków (jak wspomniano powyżej przez T.C.). –

Odpowiedz

10

Jeśli klasa zawiera obiekty ruchome (takie jak wektor), a potem po prostu niech kompilator generuje ukryte operacje pojedynek. Zrobią to, co trzeba, przesuwając każdy podobiekt.

Będziesz musiał napisać własny, jeśli samodzielnie żonglujesz surowymi wskaźnikami obiektów dynamicznych lub innych niezarządzanych uchwytów zasobów. Najlepszym rozwiązaniem jest posiadanie obiektu, który można poprawnie kopiować/przenosić (takiego jak kontener, inteligentny wskaźnik lub inna klasa RAII) w celu zarządzania każdym z nich; wtedy złożony obiekt zbudowany przez komponowanie tych elementów będzie niejawnie mieć prawidłową semantykę kopiowania/przenoszenia.

(Jak zauważono w komentarzach: jeśli twoja klasa deklaruje własny destruktor lub operacje kopiowania, to nie będzie wykonywać ukrytych operacji przenoszenia, musisz zdefiniować własne, ale jeśli zastosujesz się do powyższych wskazówek, komponując go z poprawnie zarządzanych typów, które nie wymagają specjalnej obsługi, wtedy nie powinieneś zadeklarować żadnej z tych rzeczy.)

+0

Więc pozwalając kompilatorowi wygenerować go implicitley jest nadal wystarczająco wydajny? Czy powinienem używać wskaźników? – wjk2a1

+3

@ wjk2a1: Użycie niejawnej wersji będzie prawdopodobnie bardziej skuteczne niż wprowadzenie dodatkowego poziomu pośredniego, a na pewno prostszego i mniej podatnego na błędy. Jeśli naprawdę musisz się martwić o koszt pojedynczych aktualizacji wskaźnika, musisz samodzielnie zmierzyć koszty obu podejść. –

+0

bardzo pomocna, dziękuję! – wjk2a1

3

Konstruktor ruchu stosuje podobne wytyczne, co konstruktorzy kopiowania. Jest to wymagane, gdy twoja klasa przechowuje członków za pomocą wskaźnika lub innych delikatnych pól danych (gniazd, połączeń db itp.), Tak że automatycznie wygenerowany jeden mógłby zepsuć układ pamięci, usuwając dwa razy ten sam obiekt. Więc jeśli nie masz żadnych pól wskaźnika, nie musisz pisać konstruktora ruchu.

1

Domyślny konstruktor ruchu i przeniesienie przypisania wygenerowane przez kompilator wywoła konstruktor ruchu/przypisanie dla każdego elementu klasy.

Jeśli twoja klasa ma tylko surowe elementy, na przykład "bufor char *", musisz napisać własne operacje przenoszenia.

Jeśli twoja klasa ma tylko "członków zarządzanych", na przykład "wektor", domyślne operacje przeniesienia dla twojej klasy będą ok, ponieważ deleguje operację do każdego członka.

Jeśli klasa „udało członków” mieszane z „surowych członków”, wektor i int * Na przykład, operacje przewozowe będą musiały zrobić ręczny ruch surowych środków i wywołać operacje ruch dla zarządzanych obiektów:

class MyObject { 
public: 
    // ... 


    MyObject(MyObject&& other) : vector1(std::move(other.vector1)) { 
     // We use vector's move constructor^

     // and then move ourself the char* buffer 
     buffer1 = other.buffer1; 
     other.buffer1 = nullptr;   
    } 

    MyObject& operator=(MyObject&& other) { 
     // We use vector's move asignment operator 
     vector1= std::move(other.vector1); 

     // and then move ourself the char* buffer 
     std::swap(buffer1,other.buffer1); 
     return *this; 
    } 

    //... 
private: 
    vector<char> vector1; 
    char * buffer1; 
}; 

std :: move (other.vector1) jest potrzebny ponieważ wewnątrz że funkcja other.vector1 jest lwartością. Musimy powiedzieć kompilatorowi, że nie użyjemy wartości wektora1 później w kodzie funkcji, aby można było przenieść jej wartość.

Powiązane problemy