2010-11-26 3 views
2

Je cherche une syntaxe comme ceci:Y at-il une copie explicite

class Hugo 
{ 
    Hugo(); 
    explicit Hugo(const Hugo& hugo); 

    Hugo GetRandomHugo() 
    { 
     Hugo hugo; 
     hugo.value = rand(); 
            // this would fail: 
            // return hugo; 

     return Hugo(hugo);  // explicit copy!! 
    } 
};

Autrement dit: Je suis à la recherche d'une syntaxe de copie explicite, pour permettre des méthodes de retourner une copie, même si mon Le constructeur de la copie est explicite. Je utilise GCC 4.4.5.

Merci beaucoup,

Charly

+1

Quel est le problème avec le code tel quel? – Puppy

+0

Y a-t-il une sorte d'erreur? – jwueller

+0

Pourquoi le constructeur de votre copie est-il explicite? Et pourquoi dire: "Je veux que mon constructeur de copie soit explicite mais je veux aussi effectuer des copies implicites"? Le but de rendre un constructeur explicite est d'empêcher la conversion implicite, mais un constructeur de copie ne "convertit" vraiment rien, il est là pour supporter l'initialisation, le passage d'argument, etc. –

Répondre

5

Vous ne pouvez pas: un retour en valeur est une construction de copie implicite . Ici, le retour tente de copier implicitement votre fichier temporaire construit explicitement.

de 8,5/12:

The initialization that occurs in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and brace-enclosed initializer lists (8.5.1) is called copy-initialization and is equivalent to the form :

T x = a;

+0

N'aurait-il pas de sens, d'avoir une telle syntaxe - dire au compilateur: "Oui, je veux copier explicitement" – Charly

+1

@Charly: nous avons 'T x (a)' (initialisation directe, qui est ce que vous a écrit). En un sens, le problème ici est que l'instruction 'return' cache 'une initialisation supplémentaire qui est * nécessairement * une initialisation de copie. – icecrime

+0

@Charly: pourquoi le ferait-il? Dans tous les cas, les copies doivent être gérées de manière transparente puisque le compilateur est autorisé à les éviter (mais il doit encore trouver un constructeur de copie accessible). –

1
return Hugo(hugo); 

ce juste crée une copie supplémentaire avant retour. La déclaration de retour réelle prend alors cette copie et la copie de nouveau . Tout le point dans le constructeur de copie est qu'il peut être utilisé implicitement, chaque fois que nous ou le compilateur besoin d'un objet copié.

Si vous voulez une syntaxe explicite, vous pouvez simplement ajouter une fonction Clone() ou Copy() à la classe, mais elle ne peut pas remplacer le constructeur de la copie.

Chaque fois que le compilateur a besoin de copier un objet (par exemple en le passant en valeur en tant que paramètre de fonction ou en le renvoyant d'une fonction), il doit créer une copie de l'objet. Vous ne pouvez pas le faire pour le compilateur, car vous ne voyez pas le code de "transition" entre l'appelant et l'appelé. Vous pouvez copier l'objet autour de à l'intérieur de la fonction appelée, ou à l'extérieur, mais vous n'avez aucun moyen de copier du corps de l'appelé vers l'appelant. Seul le compilateur peut faire cela, et pour ce faire, il doit être capable de copier l'objet à volonté - ce qui est fait par le constructeur de la copie.

3

Vous pouvez contourner ce problème en ayant une classe HugoCopy explicite comme ce qui suit

class HugoCopy; 
class Hugo { 
public: 
    Hugo() { ... } 
    Hugo(HugoCopy const&); 
    explicit Hugo(Hugo const&) { ... } 
}; 

struct HugoCopy { 
    HugoCopy(Hugo const& hugo) 
     :hugo(hugo) 
    { } 

    Hugo const& hugo; 
}; 

Hugo::Hugo(HugoCopy const&) { ... } 

Maintenant, la sémantique suivante appliquent

Hugo a; 
Hugo b = a; // forbidden 
Hugo c(a); // allowed 
Hugo d = HugoCopy(a); // allowed 

Hugo f() { 
    Hugo a; 
    return a; // forbidden 
    return HugoCopy(a); // allowed 
} 

Vous pouvez également utiliser une fonction de conversion

class Hugo { 
public: 
    Hugo() { ... } 
    explicit Hugo(Hugo const&) { ... } 
}; 

struct HugoCopy { 
    HugoCopy(Hugo const& hugo) 
     :hugo(hugo) 
    { } 
    operator Hugo const&() { return hugo; } 

private: 
    Hugo const& hugo; 
}; 

Cela repose sur un coin subtil de la langue C++ ge. Donc, si vous utilisez ceci, vous savez mieux ce que vous faites ou vous ne le faites pas: Il appelle d'abord la fonction de conversion sur HugoCopy (ou dans le premier cas, le constructeur de Hugo) pour obtenir un Hugo/Hugo const&, et puis initialise l'objet de destination Hugo avec cet objet Hugo. GCC n'aime pas le code, mais Clang et Comeau/EDG l'acceptent selon la sémantique ci-dessus.