Comment puis-je rendre cet object C ++ non copiable?

Voir le titre.

J’ai:

class Foo { private: Foo(); public: static Foo* create(); } 

Que dois-je faire à partir d’ici pour rendre Foo non copiable?

Merci!

 class Foo { private: Foo(); Foo( const Foo& ); // non construction-copyable Foo& operator=( const Foo& ); // non copyable public: static Foo* create(); } 

Si vous utilisez boost, vous pouvez également hériter de la non-copie: http://www.boost.org/doc/libs/1_41_0/boost/noncopyable.hpp

EDIT: C ++ 11 version si vous avez un compilateur prenant en charge cette fonctionnalité:

 class Foo { private: Foo(); Foo( const Foo& ) = delete; // non construction-copyable Foo& operator=( const Foo& ) = delete; // non copyable public: static Foo* create(); } 

Rendez également le constructeur de copie et l’opérateur d’affectation privé. La déclaration suffit, vous n’avez pas à fournir d’implémentation.

Juste un autre moyen pour interdire le constructeur de copie, Pour plus de commodité, une macro DISALLOW_COPY_AND_ASSIGN peut être utilisée:

 // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ void operator=(const TypeName&) = delete 

Ensuite, dans la classe Foo:

 class Foo { public: Foo(int f); ~Foo(); private: DISALLOW_COPY_AND_ASSIGN(Foo); }; 

ref de google feuille de style

 #include  class Foo : boost::noncopyable {... 

Mais comme l’a dit Scott Meyers … “C’est un bon cours, c’est juste que je trouve le nom un peu faux, non-naturel”, ou quelque chose comme ça.

Ajouter un peu là.

La solution traditionnelle est, comme on l’a dit, de déclarer à la fois le Copy Constructor et l’ Assignment Operator comme private , et non de les définir .

  • Parce qu’elles sont private , cela entraînera une erreur de compilation de la part de toute personne essayant de les utiliser et n’ayant pas access aux parties privées de la classe …
  • Ce qui laisse les amis (et la classe elle-même) pour lesquels l’erreur se produira sous la forme d’ undefined symbol , soit au moment du lien (si vous vérifiez ceux là) ou probablement au moment de l’ exécution (en essayant de charger la bibliothèque) .

Bien sûr, cela pose un problème dans le second cas, car vous devez ensuite vérifier vous-même votre code car vous ne disposez pas de l’indication du fichier et de la ligne sur lesquels l’erreur s’est produite. Heureusement, il est limité à vos méthodes de classe et à vos amis.


En outre, il convient de noter que ces propriétés sont transitives dans la route d’inheritance et de composition: le compilateur ne générera que les versions par Default Constructor , du Copy Constructor , de l’ Assignment Operator et du Destructor .

Cela signifie que pour chacun de ces quatre, ils sont automatiquement générés uniquement s’ils sont accessibles pour toutes les bases et tous les atsortingbuts de la classe.

 // What does boost::noncopyable looks like > class Uncopyable { public: Uncopyable() {} private: Uncopyable(const Uncopyable&); Uncopyable& operator=(const Uncopyable&); }; 

C’est pourquoi l’inheritance de cette classe (ou son utilisation en tant qu’atsortingbut) empêchera effectivement votre propre classe d’être copiable ou assignable à moins que vous ne définissiez ces opérateurs vous-même.

En général, l’inheritance est choisi sur la composition pour 2 raisons:

  • L’object est effectivement Uncopyable , même si le polymorphism peut ne pas être utile
  • L’inheritance mène à l’ Empty Base Optimization EBO ou Empty Base Optimization , tandis qu’un atsortingbut sera adressable et occupera donc la mémoire (dans chaque instance de la classe) même s’il n’en a pas réellement besoin, le compilateur a la possibilité de ne pas append cette surcharge à une base classe.

Vous pouvez également déclarer les opérateurs privés et ne pas les définir dans votre propre classe, mais le code serait moins auto-documenté et vous ne seriez pas en mesure de rechercher automatiquement les classes qui possèdent cette propriété (à moins que vous n’ayez une parsingur à part entière).

J’espère que cela éclairera le mécanisme.

En C ++ 11, vous pouvez désactiver explicitement la création du constructeur de copie et d’affectation par défaut en plaçant = delete après la déclaration.

De Wikipedia :

 struct NonCopyable { NonCopyable() = default; NonCopyable(const NonCopyable&) = delete; NonCopyable & operator=(const NonCopyable&) = delete; }; 

La même chose vaut pour les cours bien sûr.

La méthode habituelle pour rendre un object C ++ non-redimensionnable consiste à déclarer explicitement un constructeur de copie et un opérateur d’assignation de copie sans les implémenter. Cela empêchera le compilateur de générer ses propres fichiers. (En général, cela est fait en même temps que la déclaration private afin qu’elle génère une erreur de compilation au lieu d’une erreur de l’éditeur de liens.)

Il y a aussi la classe boost::noncopyable dont vous pouvez hériter, qui fait ce que j’ai décrit ci-dessus.

Rendez le constructeur de copie privé.

 Foo(const Foo& src); 

Vous n’avez pas besoin de l’implémenter, déclarez-le simplement dans le fichier d’en-tête.

C’est ce que j’utilise:

 /* Utility classes */ struct NoCopy { public: NoCopy() {} private: NoCopy(const NoCopy &); }; struct NoAssign { private: NoAssign &operator=(const NoAssign &); }; struct NonInstantiable { private: NonInstantiable(); }; struct NoCopyAssign : NoCopy, NoAssign { }; typedef NoCopyAssign NoAssignCopy; 

Dans ton cas:

 struct Example : NoCopy { }; 

La bonne pratique en C ++ 11 consiste à déclarer le constructeur et l’affectation de copie comme supprimés publiquement. Non supprimés en privé, supprimés publiquement : https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-delete