smartPointer
-
Ich habe mal versucht eine eigene kleine smartPointer Klasse zu bauen um besser vertehen zu können was da genau passiert.
Erst mal meine Klasse:
Header:#ifndef __SMARTPOINTER_H__
#define __SMARTPOINTER_H__template< typename T > class smartPointer { private: T* ptr; public: smartPointer( ); smartPointer( T* value ); ~smartPointer( ); T* operator->( ) const; T operator*( ) const; }; #endif __SMARTPOINTER_H__include "SmartPointer.h" template< typename T > smartPointer< T >::smartPointer( ) { ptr = NULL; cout << "Called !" << endl; } template< typename T > smartPointer< T >::smartPointer( T *value ) { ptr = value; cout << "Called !" << endl; } template< typename T > smartPointer< T >::~smartPointer( ) { cout << "DESTROYED !" << endl; delete ptr; } template< typename T > T smartPointer< T >::operator *( ) const { return *ptr; } template< typename T > T* smartPointer< T >::operator ->( ) const { return ptr; }Meine Main:
#include <windows.h> #include <iostream> #include "SmartPointer.h" #include "SmartPointer.cpp" using namespace std; class MYTESTCLASS { public: MYTESTCLASS( ) { } ~MYTESTCLASS( ) { } void Aus( ) { cout << "Ich bin aus MYTESTCLASS !" << endl; } }; int main( int arg, char* arvg[ ] ) { smartPointer< MYTESTCLASS > xc( new MYTESTCLASS ); xc->Aus( ); { smartPointer< MYTESTCLASS > xx( xc ); xx->Aus( ); } xc->Aus( ); return NULL; }Nun meine Frage: Warum wird der letzt Call vor dem return NULL; noch ausgeführt? In der Console steht davor auch DESTROYED. Kann mir das jemand mal erklären?
MfG
-
Zu diesem Zeitpunkt ist nur der innere Smart-Pointer zerstört worden, der äussere lebt bis Ende
main(). Da du aber keinen Kopierkonstruktor definiert hast, führen Kopien zu undefiniertem Verhalten (da der Speicher zweifach freigegeben wird).In deinem Code könnte man einiges verbessern, hier ein paar Vorschläge:
- Bezeichner mit Unterstrichen am Anfang, wie
__SMARTPOINTER_H__, sind für Compiler und Implementierung reserviert. Verwende dochSMARTPOINTER_H. - Benutze im Konstruktor die Initialisierungsliste statt Zuweisungen.
- Verbiete Kopierkonstruktor und Zuweisungsoperator, indem du sie
privatemachst. Oder implementiere sie sinnvoll. - Mache den Konstruktor, der ein
T*nimmt,explicit, um implizite Konvertierungen von Zeigern zu verhindern. NULLsteht für den Nullpointer. Missbrauche das Literal nicht fürints, schreibereturn 0;oder gar nichts.- Du benötigst kein
<windows.h>. - Defaultkonstruktor und Destruktor mit leerer Definition werden automatisch vom Compiler generiert, du brauchst sie nicht hinzuschreiben.
#endif __SMARTPOINTER_H__ist kein gültiges C++. Du kannst aberSMARTPOINTER_Hals Kommentar einsetzen.- .cpp-Dateien solltest du nie inkludieren.
- Templatedefinitionen müssen im Header stehen. Du kannst allerdings eine separate .inl-Datei für die Implementierung verwenden und am Schluss des Schnittstellen-Headers einbinden.
- Wenn du
std::coutschon im Template benötigst, solltest du<iostream>auch bereits dort einbinden. Sonst muss der Benutzer des Templates daran denken, damit der Code kompiliert.
- Bezeichner mit Unterstrichen am Anfang, wie
-
Wow. Vielen dank. Hab einiges ausgebessert!
Wie müsste ich das mit dem Kopierkonstruktor anstellen?MfG
-
BlauBär schrieb:
Wow. Vielen dank. Hab einiges ausgebessert!
Wie müsste ich das mit dem Kopierkonstruktor anstellen?MfG
Im Idealfall verbietest du Kopien, da das meist nicht gewünscht ist. Move-Konstruktor hingegen ist ein heißer Tipp.
template< typename T > class smartPointer { ... // Kopien verbieten. smartPointer(smartPointer<T> const&) = delete; smartPointer<T>& operator=(smartPointer<T> const&) = delete; smartPointer(smartPointer<T>&& other) : ptr(other.ptr) { other.ptr = 0; } smartPointer<T>& operator=(smartPointer<T>&& other) { if(ptr == other.m_ptr) { other.ptr = 0; } else { delete ptr; ptr = other.ptr; other.ptr = 0; } return *this; } ... };So ungefähr. Keine Garantie, bin gerade etwas breit. ,)