2010-05-17 8 views
5

Pouvez-vous me aider est là définition dans la norme C++ qui décrit que l'on sera appelé constructeur ou opérateur d'affectation dans ce cas:opérateur Constructeur ou cession

#include <iostream> 

using namespace std; 

class CTest 
{ 
public: 

CTest() : m_nTest(0) 
{ 
    cout << "Default constructor" << endl; 
} 

CTest(int a) : m_nTest(a) 
{ 
    cout << "Int constructor" << endl; 
} 

CTest(const CTest& obj) 
{ 
    m_nTest = obj.m_nTest; 
    cout << "Copy constructor" << endl; 
} 

CTest& operator=(int rhs) 
{ 
    m_nTest = rhs; 
    cout << "Assignment" << endl; 
    return *this; 
} 

protected: 
int m_nTest; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
CTest b = 5; 

return 0; 
} 

Ou est-ce juste une question d'optimisation du compilateur?

+0

Peut-il y avoir une différence entre "CTest b (5)" et "CTest b = 5" selon le compilateur? –

+0

Non, la première syntaxe est la syntaxe générale C++ pour créer une instance d'une classe et fournir des arguments au constructeur. La deuxième syntaxe est juste une formulation alternative que vous pouvez utiliser si le constructeur prend exactement un argument. Il existe pour que le code C compile sans modification. – eemz

+0

@joefis pourquoi vous donnez-vous une réponse juste comme un commentaire? Pouvez-vous donner quelques preuves de ce que vous avez dit? –

Répondre

7

Ce qui se passe ici dépend un peu de votre compilateur. Il pourrait créer un objet temporaire en utilisant le constructeur int, puis copier la construction b à partir de ce temporaire. Il va très probablement échapper à l'appel du constructeur de copie. Dans aucun cas, l'opérateur d'affectation ne sera utilisé.

+1

Peut-il y avoir une différence entre "CTest b (5)" et "CTest b = 5" selon le compilateur? –

+0

@ju Oui, c'est ce que nous disons. Le premier n'utilisera pas le constructeur de copie, le second pourrait le faire. –

+0

Pouvez-vous me dire pourquoi dans le second cas, le compilateur peut décider de créer un objet CTest temporaire et d'appeler un constructeur de copie? Ma théorie était qu'en standard ces deux cas sont absolument égaux :( –

11

C'est toujours le constructeur par défaut qui prend un int appelé dans ce cas. On appelle cela une conversion implicite et est sémantiquement équivalent au code suivant:

CTest b(5); 

L'opérateur d'affectation est jamais invoqué dans une initialisation. Prenons le cas suivant:

CTest b = CTest(5); 

Ici, nous appelons le constructeur (en prenant un int) puis explicitement affecter le résultat à b. Mais encore une fois, aucun opérateur d'affectation n'est jamais appelé. Strictement parlant, les deux cas appellent le constructeur de copie après avoir créé un objet de type CTest. Mais en fait, la norme encourage activement les compilateurs à optimiser l'appel du constructeur de copie ici (§12.8/15) - en pratique, les compilateurs C++ modernes n'émettent pas d'appel copycon ici.

+4

+1, mais j'essaierais d'éviter 'default' dans la phrase 'constructeur par défaut prenant un int'. Je pense qu'il sera plus clair de dire "le constructeur int" ou "le constructeur qui prend un int". La valeur par défaut a une signification spécifique (sans argument) dans la norme. –

+0

L'opérateur d'affectation EST appelé si le constructeur et les méthodes d'opérateur d'affectation sont des codes différents. – BJovke

+0

@BJovke Non - jamais à l'intérieur d'une initialisation. –

4

CTest b = 5; est un équivalent exact de CTest b(CTest(5)); Deux constructeurs sont impliqués: l'un prenant un int (convertissant implicitement de l'entier 5), et le constructeur de la copie. L'opérateur d'affectation n'est en aucun cas impliqué ici.

Le compilateur peut très bien optimiser la copie inutile, de sorte que le résultat serait comme si vous aviez tapé CTest b(5). Par conséquent, lors de l'exécution, tous les deux voyant "Constructeur de copie" imprimé (GCC avec l'option -fno-elide-constructors) ou non (GCC par défaut) serait une sortie valide du programme.

Toutefois, conceptuellement, le compilateur est nécessaire pour vérifier si un constructeur de copie accessible et approprié existe. Le formulaire CTest b = 5; échouerait à compiler si a) le constructeur de copie est privé/protégé (non accessible) ou b) le constructeur de copie prend l'argument par référence non-const (ne peut pas accepter un temporaire de CTest(5) - VC++ peut l'accepter comme une extension de compilateur non standard, cependant).

Le moral est: il n'y a pas de moyen facile de dire où et combien de fois le constructeur de la copie est appelé dans un programme en regardant le code. La copie peut être souvent omise et, par conséquent, vous ne devez jamais compter sur les effets secondaires du constructeur de copie. Si elle fait ce qu'elle est censée faire, alors cela ne devrait pas vous importer si le compilateur élimine des appels de constructeur de copie inutiles.

Questions connexes