Selon les règles C++ 11, 6 choses (constructeur par défaut, constructeur de copie, constructeur de déplacement, affectation de copie, affectation de déplacement et destructeur) sont générées par défaut. Selon la deuxième règle, lorsqu'une copie, un déplacement ou un destructeur personnalisé est défini, ces opérations par défaut ne sont pas générées. Mais dans mon code qui suit, ce n'est pas le cas. Mais ce code ne parvient pas à compiler avec une erreur
call to implicitly deleted copy constructor of 'Uni'
Quand j'écris mon propre constructeur de copie pour Uni, tout fonctionne bien. (Il est commenté dans le code, donné à titre de référence)
Toutes les pensées très appréciées.
Enfin, je l'exécute sur Mac, Xcode avec le compilateur LLVM.
merci beaucoup...
#include <iostream>
class A
{
public:
A(int i) :num{i}
{
std::clog<< "ctor A() num = " << num << "\n";
}
A( A const &aRef)
:num{aRef.num}
{
std::clog << " copy ctor A( A const &aRef) num = " << num << "\n";
}
int value()
{
return num;
}
private:
int num;
};
class Uni
{
public:
Uni(A* aptr) : up{aptr}
{
std::clog << " ctor Uni value = " << up.get()->value() << "\n";
}
/*Uni(Uni const &uRef)
{
std::clog << " copy ctor Uni copying obj pointed by unique_ptr\n";
up.reset(uRef.up.get() ? new A{*uRef.up.get()} : nullptr);
}*/
private:
std::unique_ptr<A> up;
};
int main(int argc, const char * argv[])
{
Uni one{new A{10}};
Uni two{one}; //default copy ctor is implicitly deleted. why ?
}
Les règles C++ 11 pour la génération automatique de membres spéciaux ne sont pas aussi simples que vous les avez publiées. La distinction la plus importante est que, dans certains cas, le membre est implicitement déclaré, mais défini comme supprimé. C'est ce qui se passe dans votre cas.
C++ 11, [class.copy] §11:
Un constructeur de copie/déplacement par défaut pour une classe
X
est défini comme supprimé (8.4.3) siX
a:
- un membre variant avec un constructeur correspondant non trivial et
X
est une classe de type union,- n membre de données non statique de type classe
M
(ou un tableau de celui-ci) qui ne peut pas être copié/déplacé en raison de la résolution de surcharge (13.3), tel qu'il est appliqué au constructeur correspondant deM
, entraîne une ambiguïté ou une fonction supprimée ou inaccessible du constructeur par défaut,- une classe de base directe ou virtuelle
B
qui ne peut pas être copiée/déplacée car la résolution de surcharge (13.3), telle qu’appliquée au constructeur correspondant deB
, entraîne une ambiguïté ou une fonction qui est supprimée ou inaccessible depuis le constructeur par défaut,- toute classe de base directe ou virtuelle ou membre de données non statique d'un type avec un destructeur qui est supprimé ou inaccessible du constructeur par défaut,
- pour le constructeur de copie, un membre de données non statique de type référence rvalue, ou
- pour le constructeur de déplacement, un membre de données non statique ou une classe de base directe ou virtuelle avec un type qui n'a pas de constructeur de déplacement et qui n'est pas trivialement copiable.
(Souligner le mien)
Plus généralement, les règles applicables aux membres de classe générés automatiquement sont les suivantes:
Si la classe n'a pas de constructeur fourni par l'utilisateur, un constructeur par défaut est déclaré.
Si la classe n'a pas de constructeur de copie fourni par l'utilisateur, un est déclaré.
Si la classe n'a rien de {constructeur de copie ou de déplacement fourni par l'utilisateur, opérateur d'affectation de copie ou de déplacement fourni par l'utilisateur, destructeur fourni par l'utilisateur}, un constructeur de déplacement sera déclaré (mais voir (*) ci-dessous).
Si la classe n'a pas d'opérateur d'affectation de copie fourni par l'utilisateur, un est déclaré.
Si la classe n'a rien de {constructeur de copie ou de déplacement fourni par l'utilisateur, opérateur d'affectation de copie ou de déplacement fourni par l'utilisateur, destructeur fourni par l'utilisateur}, un opérateur d'affectation de déplacement sera déclaré (mais voir (*) ci-dessous).
Si la classe n'a pas de destructeur fourni par l'utilisateur, un est déclaré.
Tout membre déclaré automatiquement peut être défini comme défaut (faire les choses par défaut) ou défini comme supprimé (si vous essayez de l'utiliser, vous obtenez une erreur). La règle de base est "Si la version par défaut est logique, elle sera définie comme par défaut. Sinon, elle sera définie comme supprimée."
Dans ce contexte, "logique" signifie "n'essaie pas d'appeler une fonction supprimée, ambiguë, inaccessible ou autrement illégale". Par exemple, le bit standard que j'ai cité dans la première partie de cette réponse répertorie ce qui n'a pas de "sens" pour les constructeurs de copie.
En outre, un constructeur de copie ou un opérateur d'affectation de copie déclaré automatiquement est défini comme supprimé si la classe possède un constructeur de déplacement ou un opérateur d'affectation de déplacement fourni par l'utilisateur.
(*) Si un constructeur de déplacement ou un opérateur d'affectation de déplacement déclaré automatiquement était défini comme supprimé, il ne serait pas du tout déclaré. Cette règle existe de sorte qu'essayer de déplacer une telle classe revient implicitement à la copier au lieu de générer une erreur.