programowanieProgramista C++

Opisz zasady trzech i pięciu (Rule of Three / Rule of Five) w C++11 oraz ich znaczenie przy projektowaniu klas.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Zasada trzech: jeśli klasa zarządza zasobem (na przykład pamięcią), to przy jawnej implementacji jednego z następujących metod należy zaimplementować także pozostałe:

  • Destruktor
  • Konstruktor kopiujący
  • Operator przypisania kopiującego

C++11: Zasada pięciu – dodano operacje przenoszące:

  • Konstruktor przenoszący
  • Operator przypisania przenoszącego

Naruszenie tej zasady prowadzi do błędów w zarządzaniu zasobami, takich jak podwójne usunięcie lub wycieki pamięci.

Przykład kodu:

class Buffer { char* data; public: Buffer(size_t sz) : data(new char[sz]) {} ~Buffer() { delete[] data; } Buffer(const Buffer& other) : data(new char[strlen(other.data)+1]) { strcpy(data, other.data); } Buffer& operator=(const Buffer& other) { if (&other != this) { delete[] data; data = new char[strlen(other.data)+1]; strcpy(data, other.data); } return *this; } // semantyka move w C++11+: Buffer(Buffer&& other) noexcept : data(other.data) { other.data = nullptr; } Buffer& operator=(Buffer&& other) noexcept { if (&other != this) { delete[] data; data = other.data; other.data = nullptr; } return *this; } };

Pytanie podchwytliwe.

Czy wystarczy zaimplementować tylko destruktor, jeśli klasa zarządza wskaźnikiem?

Nie. Bez operacji kopiujących i przenoszących przy kopiowaniu dojdzie do podwójnego usunięcia pamięci. Na przykład:

Buffer a(10); Buffer b = a; // b i a będą usuwać ten sam wskaźnik!

Przykłady rzeczywistych błędów wynikających z nieznajomości zawirowań tematu.


Historia

W platformie agregacji danych dla telekomunikacji wszystkie klasy implementowały tylko destruktor. Po refaktoryzacji struktury miało miejsce masowe kraknięcie na podwójnym usunięciu: kopiowanie obiektów powodowało losowe zachowania.


Historia

W projekcie gry mobilnej zapomniano zaimplementować konstruktor przenoszący dla klas kontenerów bufora. Przy przenoszeniu obiekt był kopiowany, co powodowało dodatkowe kopiowanie danych i spadki wydajności.


Historia

W bibliotece serializacji struktur danych podczas zwracania obiektu z funkcji zwracany był obiekt tymczasowy, a konstruktor kopiujący wykonywał płytkie kopiowanie wskaźnika. Powstało wiele wycieków, które ujawniły się dopiero po miesiącach pracy.