K
Dman schrieb:
ok, ich hoffe ich habe die Dreierregel jetzt verstanden.
Eine copy, bzw assigment Funktion für die Klasse Map wäre folglich :
Map::Map& operator=(const Map cpy)
{
Mapx = cpy.Mapx;
Mapy = cpy.Mapy;
FreeMap();
map_Data = Allocate2DArray < int > (Mapx, Mapy);
// "Depp-copy"
for (int i = 0;i < Mapy ; i++)
{
for (int j = 0;j < Mapx ; j++)
map_Data[i][j] = cpy.map_Data[i][j];
}
return *this;
}
Wenn Du sagst "copy, bzw assigment Funktion" und dann nur den Zuweisungsoperator zeigst, hast Du dann den Kopierkonstruktor vergessen oder willst Du ihn einfach nicht zeigen? Falls ersteres: Da gehört noch ein Kopierkonstruktor dazu!
Ich hoffe, Du weißt, dass Kopierkonstruktor und Zuweisungsoperator ggf vom Compiler selbst -- eventuell falsch -- implementiert werden. Daher gibt's ja auch die Dreierregel.
So schreibt man auch keinen Zuweisungsoperator. Ich sehe zwar keinen Fehler, aber das sollte recht unperformant sein; denn wenn Du so etwas schreibst wie
a = b;
werden zwei Kopien erzeugt. Zunächst wird von b eine Kopie erzeugt (-> cpy) und dann kopierst Du den Inhalt von cpy noch nach a.
Ich verweise hier mal auf den Copy & Swap Trick.
Deine Klasse sollte (mit Copy-&-Swap) in etwa so aussehen:
class Map
{
public:
Map(); // Default-Konstruktor
Map(int xdim, int ysim);
Map(Map const&); // Kopier-konstruktor
~Map(); // Destruktor
void swap(Map & that); // Vertauscht den Inhalt zweier Objekte
Map& operator=(Map temp) { swap(temp); return *this; }
//... noch ein paar Operationen
private:
int xdim_;
int ydim_;
ElemType** elems_;
};
inline void swap(Map & a, Map & b) {a.swap(b);}
wobei man bei swap natürlich nur die zwei ints und den Zeiger austauschen muss.
Wenn du es ohne Copy-&-Swap Trick machen willst, sollte es so aussehen:
class Map
{
public:
Map(); // Default-Konstruktor
Map(int xdim, int ysim);
Map(Map const&); // Kopier-konstruktor
~Map(); // Destruktor
Map& operator=(Map const& temp);
//... noch ein paar Operationen
private:
int xdim_;
int ydim_;
ElemType** elems_;
};
...
Map& Map::operator=(Map const& temp)
{
if (this==&temp) return *this; // Selbstzuweisung abfangen
...
return *this;
}
Und wenn Du das fehlerfrei geschafft hast, dann kannst Du das Ding mit 'nem STL-Container komplett neu machen:
class Map
{
public:
Map();
Map(int xdim, int ysim);
private:
int xdim_;
int ydim_;
std::vector<ElemType> elems_;
};
Beachte: Man muss hier gar keinen Kopierkonstruktor, Destruktor und Zuweisungsoperator selbst deklarieren, da die vom Compiler-generierten Versionen genau das richtige tun. Du solltest also beim Klassen-Design darauf Wert legen, dass benutzerdefinierter Destruktor und Kopier-Operationen erst gar nicht nötig sind, falls möglich.
Dman schrieb:
Wenn ich nun aber in jeder Session meines Programmes jeweils nur eine Instanz der Klasse Map enstehen lasse bin ich doch dazu befugt die Dreierregel zu brechen oder sehe ich das falsch.
Wenn so ein Objekt nicht kopieren brauchst, dann solltest Du es auch wenigstens verbieten, so dass ein Kopierversuch zu einem Kompilierfehler führt. Das kann man erreichen indem Kopierkonstruktor und Zuweisungsoperator privat deklariert werden und undefiniert bleiben -- oder alternativ die Klasse von so etwas wie boost::noncopyable erben lässt.
Mit welchem Buch lernst Du C++? Steht da so'was nicht drin? Hast Du Scott Meyers' "Effective C++" gelesen? Falls nicht, unbedingt kaufen!
kk