Объясните поведение std::map
От: alander  
Дата: 05.10.05 07:44
Оценка:
Есть следующий код:

#include <iostream>
#include <map>

class MainClass
{
public:
MainClass():val(0) { std::cerr << "MainClass()\n"; };
~MainClass() { std::cerr << "~MainClass()\n"; };

void print() { std::cerr << "value = " << val << "\n"; };

int val;
};

int main(int argc, char **argv)
{
std::map<int,MainClass> mainmap;

std::cerr << "mainmap[0]\n";
mainmap[0];
std::cerr << "mainmap[0].print()\n";
mainmap[0].print();
std::cerr << "return 0\n";
return 0;
}

Который выводит на экран следующее:
mainmap[0]
MainClass()
~MainClass()
~MainClass()
mainmap[0].print()
MainClass()
~MainClass()
~MainClass()
value = 0
return 0
~MainClass()

Вопрос такой: откуда берутся дестркуторы после вызовов mainmap[0] и mainmap[0].print(), почему их по 2? И вообще, почему количество деструкторов != количеству конструкторов?!
Re: Объясните поведение std::map
От: crable США  
Дата: 05.10.05 07:56
Оценка:
Здравствуйте, alander, Вы писали:

A>Есть следующий код:


A>#include <iostream>

A>#include <map>

A>class MainClass

A>{
A> public:
A> MainClass():val(0) { std::cerr << "MainClass()\n"; };
A> ~MainClass() { std::cerr << "~MainClass()\n"; };

A> void print() { std::cerr << "value = " << val << "\n"; };


A> int val;

A>};

A>int main(int argc, char **argv)

A>{
A> std::map<int,MainClass> mainmap;

A> std::cerr << "mainmap[0]\n";

A> mainmap[0];
A> std::cerr << "mainmap[0].print()\n";
A> mainmap[0].print();
A> std::cerr << "return 0\n";
A> return 0;
A>}

A>Который выводит на экран следующее:

A>mainmap[0]
A>MainClass()
A>~MainClass()
A>~MainClass()
A>mainmap[0].print()
A>MainClass()
A>~MainClass()
A>~MainClass()
A>value = 0
A>return 0
A>~MainClass()

A>Вопрос такой: откуда берутся дестркуторы после вызовов mainmap[0] и mainmap[0].print(), почему их по 2? И вообще, почему количество деструкторов != количеству конструкторов?!

А ты добавь в MainClass вот это:

MainClass(MainClass const &other): val(other.val) { std::cerr<< "MainClass(other)\n"; }
The last good thing written in C was Franz Schubert's Symphony No. 9.
Re: Объясните поведение std::map
От: StepanM Россия  
Дата: 05.10.05 08:03
Оценка:
Здравствуйте, alander, Вы писали:

A> ...


A>Вопрос такой: откуда берутся дестркуторы после вызовов mainmap[0] и mainmap[0].print(), почему их по 2? И вообще, почему количество деструкторов != количеству конструкторов?!


Объекты класса MainClass создаются не только через конструктор по умолчанию (который ты явно определил), но и через конструктор копирования (который ты явно не определил, но который тем не менее определен не явно компилятором). Для того, чтобы увидеть работу конструктора копирования, ты должен явно переопределить его в своем классе.

class MainClass
{
...
MainClass(const MainClass& other): val(other.val) { std::cerr << "MainClass(const MainClass& other)\n"; };
...
}

После этого количество деструкторов должно сравняться с количеством конструкторов.
Re[2]: Объясните поведение std::map
От: alander  
Дата: 05.10.05 08:04
Оценка:
О, точно, спасибо!
Re: Объясните поведение std::map
От: Phoenickx  
Дата: 05.10.05 08:14
Оценка:
Здравствуйте, alander, Вы писали:

A>Есть следующий код:


<skip>

А какой комплиятор?
Под VS2003 проверял, там вызывается еще копирующий конструктор, причем дважды (в опретаторе []):


#include <iostream>
#include <map>

class MainClass
{
public:
MainClass():val(0) 
{ 
    std::cerr << "MainClass()\n"; 
};
MainClass(const MainClass& mc)
{
    std::cerr<<"copy constructor\n";
}
~MainClass() 
{ 
    std::cerr << "~MainClass()\n"; 
};

void print() { std::cerr << "value = " << val << "\n"; };

int val;
};

int main(int argc, char **argv)
{
    {
std::map<int,MainClass> mainmap;

std::cerr << "mainmap[0]\n";
mainmap[0];
std::cerr << "mainmap[0].print()\n";
mainmap[0].print();
std::cerr << "return 0\n";
    }
getchar();
return 0;
}


вывод таков:

MainClass()
copy constructor
copy constructor
~MainClass()
~MainClass()
mainmap[0].print()
value = -842150451
return 0
~MainClass()
Re: Объясните поведение std::map
От: Bell Россия  
Дата: 05.10.05 09:19
Оценка:
Здравствуйте, alander, Вы писали:

Ну, про конструктор копирования уже ответили, так что я попробую ответить на вот этот вопрос:
A>Вопрос такой: откуда берутся дестркуторы после вызовов mainmap[0] и mainmap[0].print(), почему их по 2?

Дело в том, что operator[] в std::map реализован следующим образом:

23.3.1.2 map element access
 
T& operator[](const key_type& x);

1 Returns: (*((insert(make_pair(x, T()))).first)).second.


Как видишь, при вызове operator[], создается как раз 2 временных объекта типа T, т.е. MainClass в данном случае.

ЗЫ
попробуй этот пример в release-конфигурации, возможно, что твой компилятор сумеет что-нибудь соптимизировать.
Любите книгу — источник знаний (с) М.Горький
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.