7

Oto bardzo prosty sposób zdefiniować zadanie ruch na niemal każdej klasy z konstruktora ruch:Czy przypisanie ruchu przez destruct + move konstrukcja jest bezpieczne?

class Foo { 
public: 
    Foo(Foo&& foo);      // you still have to write this one 
    Foo& operator=(Foo&& foo) { 
    if (this != &foo) {    // avoid destructing the only copy 
     this->~Foo();     // call your own destructor 
     new (this) Foo(std::move(foo)); // call move constructor via placement new 
    } 
    return *this; 
    } 
    // ... 
}; 

Czy ta sekwencja nazywając swoją destruktora a następnie umieszczenie nowego na ten wskaźnik bezpieczny w standardzie C++ 11 ?

+2

Twój konstruktor ruchu powinien być "noexcept", inaczej spróbujesz zniszczyć już zniszczony obiekt, jeśli rzuci i odejdzie w UB-land. – ildjarn

+1

Dobra sztuczka do przenoszenia/kopiowania jest po prostu [weź parametr według wartości] (http://stackoverflow.com/questions/9746748/does-it-make-sense-to-reuse-destructor-logic-by- using-stdswap-in-a-move-assign/9746772 # 9746772). Użytkownik albo przeniesie - skonstruuje parametr wartości, albo skopiuje - skonstruuje (lub wymusi na nim). Następnie możesz użyć 'std :: swap' do zamiany wartości na obiekt. –

Odpowiedz

6

Tylko jeśli nigdy, przenigdy nie wypiszesz typu z tej klasy. Jeśli to zrobisz, zmieni to obiekt w potworność. Szkoda, że ​​standard używa tego jako przykładu do objaśniania okresów życia obiektów. Naprawdę źle jest robić w prawdziwym kodzie.

+0

Czy jest też problem z zajęciem nowej pamięci, ręcznym jej zapisem, a następnie umieszczeniem w nowym miejscu? Musiałbym użyć standardowego interfejsu, aby sprawdzić, czy jest to dozwolone. – Yakk

+0

@Tak, nie, ponieważ nie przyznajesz niczego. –

+0

@Tak, nie powinno być problemu w tym zakresie, o ile obiekt, który pierwotnie przydzielono, ma wymagania dotyczące rozmiaru i wyrównania wystarczające dla obiektu, który utworzysz poprzez umieszczenie nowego, a wskaźnik, który przekazujesz do usunięcia, jest odpowiedniego typu. – bames53

0

Technicznie kod źródłowy jest bezpieczny w tym małym przykładzie:. Ale rzeczywistość jest taka, że ​​jeśli kiedykolwiek spojrzysz na Foo śmiesznie, powołasz się na UB. Jest tak ohydnie niebezpieczne, że nie jest tego warte. Po prostu używaj wymiany jak wszyscy inni - jest ku temu powód i dlatego, że jest to właściwy wybór. Sprawdzanie samo-przydziału jest złe.

+2

Kopiowanie i wymiana nie zawsze są najlepszą implementacją. Jest to prosty sposób uzyskania silnej gwarancji wyjątku bezpieczeństwa, ale są kompromisy. Howard Hinnant omawia je częściowo w odpowiedzi [this] (http://stackoverflow.com/a/6687520/365496). – bames53

+0

Czy problem dotyczy głównie autora klasy pochodnej (błędnie w tym przypadku) wywołującego zadanie przeniesienia Foo, czy też jest więcej problemów? Technika ta wymaga od autorów podklasowych, aby ominęli wirtualnie i użyli tej techniki.Większość problemów, które mogę wymyślić poza tym, że przypisanie przeniesienia nie jest wirtualne, a następnie odpowiedź brzmi tylko, że przeniesienie przypisania powinno być wirtualne w tych przypadkach, niezależnie od tego, czy ta technika jest używana (zgadzasz się?). Czy masz obawy poza tym? –

Powiązane problemy