006
07.06.2004, 12:50 Uhr
virtual
Sexiest Bit alive (Operator)
|
@stepanw Also "exceptionsicher" bedeutet ja nicht, daß niemals eine Exception auftreten darf, sondern daß alle involvierten Objekte im Falle einer Exception noch konsistent bleiben. Ich mach es mal anhand folgenden Beispiel deutlich: Erstmal die naive Methode (nicht exception sicher):
C++: |
class String { private: char* ptr; public: String(const char* ptr_) { ptr = new char[strlen(ptr_)+1]; strcpy(ptr, ptr_); } ~String() { delete[] ptr; } String& operator = (const String& src) { delete[] ptr; ptr = new char[strlen(src.ptr)+1]; // HIER strcpy(ptr, src.ptr); return *this; } };
|
Das Problem ist die mit HIER gekennzeichnete Zeile: hier könnte ein std::bad_alloc geworfen werden, in der Folge wäre this in einem nicht konsitenten Zustand, weil ptr bereits freigegeben wurde, also ein dangling Pointer ist, der im dtor zu Problemen führen würde. Das Problem könnte man hier natürlich umgehen:
C++: |
String& operator = (const String& src) { char* tmp = new char[strlen(src.ptr)+1]; // Eception kann geworfen werden, aber this ist noch konsistent delete[] ptr; ptr = tmp; strcpy(ptr, src.ptr); return *this; }
|
Also einen Umweg über eine lokale Variable gehen. Im Prinzip macht dieser swap Ansatz ja nichts anderes, nur eben auf eine mehr oder wenig generische Art:
C++: |
class String { private: char* ptr; public: void swap(String& other) { std::swap(ptr, other.ptr); } String(const char* ptr_) { ptr = new char[strlen(ptr_)+1]; strcpy(ptr, ptr_); } String(const String& src) { ptr = new char[strlen(src.ptr)+1]; strcpy(ptr, src.ptr; } ~String() { delete[] ptr; } String& operator = (const String& src) { String tmp(src); // HIER swap(tmp); return *this; } };
|
Die einzige Stelle, wo hier jetzt eine Exception auftreten könnte, wäre die mit HIER markierte Stelle (copyctor könnte eine werfen). Das ist aber völlig unkritisch, weil weder this noch src dadurch verändert würden. -- Gruß, virtual Quote of the Month Ich eß' nur was ein Gesicht hat (Creme 21) |