2010-06-21 4 views
8

Le constructeur et l'affectation de copie de l'objet racine du MFC sont désactivés par défaut.Pourquoi désactiver le constructeur et l'affectation de copie de CObject

Le constructeur de la classe standard par défaut C de copie fait un membre par membre copie. La présence du constructeur de copie CObject garantit un message d'erreur de compilateur si le constructeur de la copie de votre classe est requis mais pas disponible. Vous devez donc fournir un constructeur de copie si votre classe requiert cette fonctionnalité.

  • Dans le code source de CObject, il y a un commentaire:

Désactiver le constructeur de copie et cession par défaut de sorte que vous obtiendrez des erreurs du compilateur au lieu de comportement inattendu si vous passez des objets par valeur ou affecter des objets.

Ma question est, quel est le problème avec le constructeur de copie bit par bit par défaut pour cette classe CObject? À mon avis, il serait préférable de nous donner le constructeur de copie par défaut, et nous pourrions fournir un si nécessaire (copie en profondeur)

+0

mieux supprimer l'étiquette MFC pour attirer plus d'utilisateurs –

+1

La réponse est susceptible d'être spécifique à MFC, cependant. – peterchen

+0

Merci, ça marche !!! –

Répondre

6

La valeur par défaut constructeur de copie est membre par membre, et non au niveau du bit.

La plupart des classes dérivées de CObject contiennent - et gèrent directement - des ressources système qui n'ont pas de comptage de références ou mécanisme similaire, donc le choix a probablement été fait en pensant au cas d'utilisation par défaut.

par exemple. CGdiObject est à peu près:

class CGDIObject : public CObject 
{ 
    HGDIOBJ m_handle; 

    CGDIObject() : m_handle(0) {} 
    // derived classes provide a create, attach etc. 
    ~CGDIObject() { DeleteObject(m_handle); } 
} 

Le constructeur de copie par défaut ici serait dangereux (conduisant à la destruction à double), avec un constructeur de copie « correcte » est étonnamment difficile et coûteux.

Une autre raison peut être que la plupart des classes dérivées de CObject sont destinées à être mutées, et donc transmises par référence.Un constructeur de copie manquante attraper des copies non intentionnelles qui mutent une copie plutôt que l'objet est passé:

class CMyObject : public CObject 
{ 
    public: 
     AttachFoo(FooHandle foo) { ... } 
     AddBar() { ... } 
}; 

bool InitMySession(CMyObject & obj) 
{ 
    obj.AttachFoo(CreateRawFoo()); 
    obj.AddBar(); 
    obj.AddBar(); 
} 

// ... 
CMyObj mo; 
InitMySession(mo); 

Omettre la « & » vous donne le code qui compile bien, mais crée une copie temporaire, modifie que, puis laisse tomber , tandis que mo reste non modifié. MFC ne s'appuie pas sur des exceptions pour la gestion des erreurs (pour des raisons historiques: tous les compilateurs ciblés ne les supportent pas bien, et MFC nécessite beaucoup de ressources supplémentaires qui deviennent douloureuses avec des exceptions).


Je ne pense pas que ces choix soient bons, par ex. les classes dérivées devraient être autorisées à utiliser le constructeur de copie par défaut si leurs membres le permettent (et la plupart des membres devraient le permettre). La décision correspond à la "mentalité" de MFC, cependant, et les requriements/restrictions du temps MFC a été créé.

+0

bon point, la relation étroite entre MFC et ces ressources du système peut les laisser décider de le faire. Je n'ai pas bien compris votre deuxième point, que voulez-vous dire en parlant de mutation? –

+0

ajouté plus de détails – peterchen

3

Considérez ce qui suit:

class CMyHandle : public CObject 
{ 
    HANDLE hWin32; 
public: 
    CMyHandle() 
    { 
     hWin32 = SomeFunctionThatMakesHandle(); 
    } 
    ~CMyHandle() 
    { 
     CloseHandle(hWin32); 
    } 
}; 

Maintenant, si vous copiez CMyHandle, la handle finit par se fermer deux fois et après que l'une des instances CMyHandle est détruite, l'autre instance devient invalide.

Étant donné qu'un grand nombre de classes MFC gèrent les handles, il est logique de forcer le créateur de la classe à remplacer explicitement les constructeurs de copie et les opérateurs d'affectation de copie.

EDIT: Par exemple:

int main() 
{ 
    CMyHandle h1; //CMyHandle's constructor initializes the handle 
    { 
     CMyHandle h2(h1); //Memberwise copy into h2. In this case, it copies the 
          //handle 
    } //h2 destroyed, closes handle 
    //h1 is now invalid (because the underlying handle was closed)! 
} 
Questions connexes