Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

ajout d'un objet dans une et destructeur

4 réponses
Avatar
Benoit Izac
Bonjour,

============================================================================
#include <map>
#include <sstream>
#include <string>
#include <iostream>

int nb_constr = 0;
int nb_constr_param = 0;
int nb_destr = 0;

class test {
public:
test();
test(const int&);
~test();
private:
int value;
};

test::test()
{
value = -1;
std::cout << " constructor (" << value << ") ("
<< ++nb_constr << ")" << std::endl;
}

test::test(const int& i)
{
value = i;
std::cout << " constructor with param (" << value << ") ("
<< ++nb_constr_param << ")" << std::endl;
}

test::~test()
{
std::cout << " destructor (" << value << ") ("
<< ++nb_destr << ")" << std::endl;
}

int main()
{
std::map<std::string, test> m;
for (int i = 0; i < 5; ++i) {
std::cout << "creation" << std::endl;
test t(i);

std::string s;
{
std::ostringstream oss;
oss << i;
s = oss.str();
}

std::cout << "affectation" << std::endl;
m[s] = t;

std::cout << "end of loop" << std::endl;
}
return 0;
}
============================================================================

Pouvez-vous m'expliquer la magie dans « m[s] = t » ?

Je comprends le premier constructeur comme la création d'un objet test
pour y copier ensuite le contenu de t. En revanche, je ne comprends pas
les deux destructeurs qui suivent...

Merci.
--
Benoit Izac

4 réponses

Avatar
James Kanze
On Monday, 8 July 2013 15:12:49 UTC+1, Benoit Izac wrote:
Bonjour,

======================== ========================= ========================= ==
#include <map>
#include <sstream>
#include <string>
#include <iostream>

int nb_constr = 0;
int nb_constr_param = 0;
int nb_destr = 0;

class test {
public:
test();
test(const int&);



Si tu veux tracker tous les appels à des constructeurs, il faut
y ajouter celui qui serait fourni autrement par le compilateur :

test( test const& other );

~test();
private:
int value;
};

test::test()
{
value = -1;
std::cout << " constructor (" << value << ") ("
<< ++nb_constr << ")" << std::endl;
}

test::test(const int& i)
{
value = i;
std::cout << " constructor with param (" << value << ") ("
<< ++nb_constr_param << ")" << std::endl;
}



Et l'implémentation de celui qu'on a ajouté :

test::test( test const& other )
: value( other.value )
{
std::cout << " copy constructor (" << value << ") (""
<< ++nb_constr_param << ")" << std::endl;
}

(Je dirai, en passant, que dans ce genre de case, c'est souvent
utile d'y ajouter un " << this "" dans ce qu'on sort.)

test::~test()
{
std::cout << " destructor (" << value << ") ("
<< ++nb_destr << ")" << std::endl;
}

int main()
{
std::map<std::string, test> m;
for (int i = 0; i < 5; ++i) {
std::cout << "creation" << std::endl;
test t(i);

std::string s;
{
std::ostringstream oss;
oss << i;
s = oss.str();
}

std::cout << "affectation" << std::endl;
m[s] = t;

std::cout << "end of loop" << std::endl;
}
return 0;
}
======================== ========================= ========================= ==

Pouvez-vous m'expliquer la magie dans "m[s] = t" ?

Je comprends le premier constructeur comme la création d'un objet test
pour y copier ensuite le contenu de t. En revanche, je ne comprends pas
les deux destructeurs qui suivent...



Ce sont des destructions des temporaires dans std::map.

Il lui en faut deux, parce que "m[s]" est l'équivalent de
"m.insert( std::make_pair( s, test() ) )". Le premier
temporaire, c'est celui qui sert de paramètre de
`std::make_pair` ; c'est celui construit par le constructeur par
défaut. Le deuxième, c'est le membre du "std::pair" construit
(par le constructeur de copie) pour le passer comme paramètre
à std::map<>::insert. Un troisième serait construit comme partie
de l'entrée dans le map, mais celui-là n'est pas un temporaire ;
il perdurera bien au-delà de l'expression.

--
James
Avatar
Benoit Izac
Bonjour,

le 10/07/2013 à 18:33, James Kanze a écrit dans le message
:

Pouvez-vous m'expliquer la magie dans "m[s] = t" ?



Je comprends le premier constructeur comme la création d'un objet test
pour y copier ensuite le contenu de t. En revanche, je ne comprends pas
les deux destructeurs qui suivent...



Ce sont des destructions des temporaires dans std::map.

Il lui en faut deux, parce que "m[s]" est l'équivalent de
"m.insert( std::make_pair( s, test() ) )". Le premier
temporaire, c'est celui qui sert de paramètre de
`std::make_pair` ; c'est celui construit par le constructeur par
défaut. Le deuxième, c'est le membre du "std::pair" construit
(par le constructeur de copie) pour le passer comme paramètre
à std::map<>::insert. Un troisième serait construit comme partie
de l'entrée dans le map, mais celui-là n'est pas un temporaire ;
il perdurera bien au-delà de l'expression.



Merci, j'ai bien compris le fonctionnement.

Concernant l'équivalence entre m[s] et m.insert(...), c'est garantie ou
c'est propre à l'implémentation ?

--
Benoit Izac
Avatar
James Kanze
On Wednesday, 10 July 2013 22:33:28 UTC+1, Benoit Izac wrote:

Concernant l'équivalence entre m[s] et m.insert(...), c'est garantie ou
c'est propre à l'implémentation ?



La norme dit simplement que "If there is no key equivalent to
x in the map, inserts value_type(x, T()) into the map."
L'implémentation triviale est:

T& operator[]( key_type const& key )
{
return *insert( value_type( key, T() ) ).first;
}

Encore que ça crée une instance de T() même si on n'en a pas
besoin. Les deux implémentations auxquels j'ai accès
n'appellent `insert` (et donc, ne créent des temporaires) que si
la clé n'est pas présent.

--
James
Avatar
espie
In article ,
James Kanze wrote:
On Wednesday, 10 July 2013 22:33:28 UTC+1, Benoit Izac wrote:

Concernant l'équivalence entre m[s] et m.insert(...), c'est garantie ou
c'est propre à l'implémentation ?



La norme dit simplement que "If there is no key equivalent to
x in the map, inserts value_type(x, T()) into the map."
L'implémentation triviale est:

T& operator[]( key_type const& key )
{
return *insert( value_type( key, T() ) ).first;
}

Encore que ça crée une instance de T() même si on n'en a pas
besoin. Les deux implémentations auxquels j'ai accès
n'appellent `insert` (et donc, ne créent des temporaires) que si
la clé n'est pas présent.



Je soupconne fortement que ca va se comporter de facon plus efficace
si on passe en C++2011...