Dear visitor, welcome to VDR Portal. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.
|
|
Source code |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
cat test.cpp
#include <stdlib.h>
#include <map>
class test
{
public:
~test()
{
printf("~test\n");
}
};
int main()
{
std::map<int,test> m_map;
// test t;
m_map[1] = *(new test());
printf("exit\n");
return 0;
}
|

|
|
Source code |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <stdlib.h>
#include <map>
class test
{
public:
~test()
{
printf("~test\n");
}
};
int main()
{
std::map<int,test*> m_map;
// test t;
m_map[1] = (new test());
printf("exit\n");
delete m_map[1];
return 0;
}
|
Quoted
Original von zuse
![]()
Source code
1 2 3 4 5 6 7 8 9 10 11 12int main() { std::map<int,test> m_map; // test t; m_map[1] = *(new test()); printf("exit\n"); return 0; }
Die Ausgabe lautet:
~test
~test
exit
~test
Quoted
Originally posted by zuse
[...]
Mir ist vollkommen unklar wieso beim Einfügen der Instanz von 'test' der Konstruktor zweimal aufgerufen wird. Die Map ist doch eigentlich nur ein Container, der den Inhalt eigentlich nicht anfassen sollte.
[...]
Quoted
Originally posted by zirias
Dass es 3 Kopien sind, ist leicht erklärt. Die erste erstellst du mit dem new-Operator. Die zweite ist ein sogenanntes temporary object: da die rechte Seite deiner Zuweisung ein Ausdruck ist (dereferenzierung von irgendwas) wird hier ein temporäres Objekt mit dem Ergebnis des Ausdrucks erstellt, dessen Lebensdauer sich auf die eine Anweisung beschränkt. Für die dritte Kopie ist dann std::map<> verantwortlich, denn das ist, wie du schon sagst, ein Container. Wenn es Objekte einer Klasse speichern soll tut es auch genau das (und speichert nicht etwa Pointer oder Referenzen), also muss es das Objekt kopieren, das gespeichert werden soll.
Quoted
Originally posted by zirias
Was mich bei deiner Ausgabe wundert ist, dass der Destruktor der ersten Kopie überhaupt aufgerufen wird. Da du den Rückgabewert von new nicht speicherst sondern direkt weiterverarbeitest (in dem Fall mit *), ist der Pointer zu deiner ersten Kopie eigentlich verloren, das sollte normalerweise ein Speicherleck sein.
This post has been edited 1 times, last edit by "crib" (Feb 1st 2008, 4:02am)
Quoted
Original von crib
m_map[1] erstellt zuerst! ein neues Objekt vom Typ 'test', fügt es in die map ein und gibt dann eine Referenz auf das neue Objekt zurück. Im nächsten Schritt wird der Assignment-Operator operator=(const test& rhs) dieses Objekts aufgerufen mit test() als Argument. Das Argument wird ebenfalls nach der Assignment-Operation zerstört.
Quoted
Das stimmt so leider nicht.
Quoted
Quoted
Originally posted by zirias
Was mich bei deiner Ausgabe wundert ist, dass der Destruktor der ersten Kopie überhaupt aufgerufen wird. Da du den Rückgabewert von new nicht speicherst sondern direkt weiterverarbeitest (in dem Fall mit *), ist der Pointer zu deiner ersten Kopie eigentlich verloren, das sollte normalerweise ein Speicherleck sein.
Der Destruktor des durch new() instantiierten Objekts wird in diesem Beispiel nie ausgefuehrt.
This post has been edited 1 times, last edit by "zirias" (Feb 4th 2008, 5:41pm)
Quoted
So ganz stimmt das immer noch nicht, die rechte Seite ist nicht test() sondern *(new test()) und damit ein temporary...
Quoted
Naja, hier war ich wohl in Gedanken bei std::vector<>::push_back(). Aber bis auf die Kopie beim Einfügen stimmt's schon...
Quoted
Das sehe ich ja genauso. Aber woher kommt der dritte Destruktor-Aufruf? Egal wie ich es drehe, ich sehe bei dem Code abgesehen vom mit new konstruierten Objekt nur zwei weitere Objekte.
|
|
Source code |
1 2 3 4 |
m_map[1] = test(); // entspricht: test& t = m_map[1]; // m_map.operator[](1) t = test(); // t.operator=(test()); |
Quoted
Original von crib
Quoted
So ganz stimmt das immer noch nicht, die rechte Seite ist nicht test() sondern *(new test()) und damit ein temporary...
Der Ausdruck "*(new test())" ist in sich bereits ein memleak und damit ein schwerer Fehler. Was du mit new allokierst, musst du auch wieder frei geben.
Aber selbst wenn du es wieder frei geben würdest, es wäre trotzdem schlechter Code. Das temporäre Objekt gehört auf den Stack, wie in meinem Beispiel!
Quoted
Quoted
Naja, hier war ich wohl in Gedanken bei std::vector<>::push_back(). Aber bis auf die Kopie beim Einfügen stimmt's schon...
Nein tut es nicht.