Mam klasę, która wymaga innego niż domyślny konstruktora kopiowania i operatora przypisania (zawiera listę wskaźników). Czy istnieje jakiś ogólny sposób ograniczenia duplikacji kodu między konstruktorem kopiowania a operatorem przypisania?Zmniejszenie duplikacji kodu między operatorem = a konstruktorem kopiującym
Odpowiedz
Nie ma „ogólny sposób” do pisania własnych konstruktorów kopiowania i operatorów przypisania, który działa we wszystkich przypadkach. Ale istnieje idiom nazywa „kopiowaniem & -swap”:
class myclass
{
...
public:
myclass(myclass const&);
void swap(myclass & with);
myclass& operator=(myclass copy) {
this->swap(copy);
return *this;
}
...
};
Jest to przydatne w wielu (ale nie wszystkich) sytuacje. Czasami możesz zrobić lepiej. Wektor lub ciąg może mieć lepsze przypisanie, które ponownie wykorzysta przydzielony obszar pamięci, jeśli jest wystarczająco duży.
+1 - dobre i lakoniczne podsumowanie wymiany kopii myślę. Dobry pomysł na ponowne wykorzystanie pamięci. –
Możesz wskazać subtelność tutaj pomiędzy operatorem = i bardziej standardowym myclass & operator = (const myclass i inne); – Bill
Funkcja swap() powinna być prawdopodobnie oznaczona jako nothrow. Komentarz Ditto on Bills. Jeszcze lepiej byłoby wyjaśnić. –
Wyróżnij wspólny kod funkcji prywatnego członka. Prosty (raczej wymyślony) przykład:
#include <iostream>
class Test
{
public:
Test(const char* n)
{
name = new char[20];
strcpy(name, n);
}
~Test()
{
delete[] name;
}
// Copy constructor
Test(const Test& t)
{
std::cout << "In copy constructor.\n";
MakeDeepCopy(t);
}
// Assignment operator
const Test& operator=(const Test& t)
{
std::cout << "In assignment operator.\n";
MakeDeepCopy(t);
}
const char* get_name() const { return name; }
private:
// Common function where the actual copying happens.
void MakeDeepCopy(const Test& t)
{
strcpy(name, t.name);
}
private:
char* name;
};
int
main()
{
Test t("vijay");
Test t2(t); // Calls copy constructor.
Test t3("");
t3 = t2; // Calls the assignment operator.
std::cout << t.get_name() << ", " << t2.get_name() << ", " << t3.get_name() << '\n';
return 0;
}
+1 - to prawie zawsze najlepszy sposób na powielenie kodu w obrębie klasy. –
wyciek pamięci! MakeDeepCopy ignoruje możliwość nazwy już wskazującej na przydzieloną pamięć. – sellibitze
Szkoda, że konstruktor kopiowania nie może korzystać z inicjalizatorów elementów, w ten sposób ... – xtofl
My &My::operator = (My temp) // thanks, sellibitze
{
swap (*this, temp);
return *this;
}
i wdrożenie specjalistycznego std::swap<> (My &, My &)
.
Oto jak powinien wyglądać plik copy - & - swap. Tworzysz wyraźnie kopię, która w innym przypadku może zostać usunięta. Tutaj jest świetny artykuł: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – sellibitze
Jak zauważa Dave, alexandrescu o tym około 6 lat temu: http : //www.ddj.com/cpp/184403855. Ciekawa lektura! –
errm, Nawiasem mówiąc plakat jest również nazywany Dave. Przykro mi z powodu zamieszania - miałem na myśli Dave'a Abrahamsa z cpp-next :) –
Jak już zostało wskazane przez kilka plakatów, posiadanie operatora = utworzenie nowego obiektu z konstruktorem kopiującym, a następnie użycie swap jest powszechnie stosowaną techniką, która nie musi replikować kodu w operatora =.
To powiedziawszy, chcę wskazać profesjonalistę i oszustę tej techniki, która pomoże ci zdecydować, czy jest to właściwe.
Pro - wyjątek bezpieczeństwa
Jeśli obiekt ma wymagań dotyczących zasobów, które mogą spowodować rzut i zakładając, że wymiany nie rzuci, technika ta stanowi silną gwarancję bezpieczeństwa wyjątków (albo obiekt jest przypisany do nabrała wartość innego obiektu lub jest niezmieniona).
Con - zasób ślad
Problem z tej techniki jest to, że wymaga to zupełnie nowy obiekt, który ma zostać utworzony przed stary zostanie zwolniony. Jeśli twój obiekt wymaga dużej ilości zasobów, może to stanowić problem.
Myślę, że powinieneś być w stanie wywołać konstruktora kopii wewnątrz operatora = –
Niektóre odpowiedzi są tutaj: http://stackoverflow.com/questions/1457842/is-this-good-code-copy-ctor-operator –