80 votes

Comment rendre cet objet C ++ non copiable?

Voir le titre.

J'ai:

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

Que dois-je faire d'ici pour que Foo ne puisse plus être copié?

Merci!

109voto

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

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

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

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

30voto

Hans Passant Points 475940

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

19voto

Chris H Points 3534
 #include <boost/utility.hpp>
class Foo : boost::noncopyable {...
 

Mais comme l'a dit un jour Scott Meyers ... "C'est une belle classe, c'est juste que je trouve le nom un peu différent, non naturel", ou quelque chose du genre.

19voto

yesraaj Points 12759

Un autre moyen d’interdire le constructeur de copie. Par 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&);               \
  void operator=(const TypeName&)
 

Ensuite, en classe Foo:

 class Foo {
 public:
  Foo(int f);
  ~Foo();

 private:
  DISALLOW_COPY_AND_ASSIGN(Foo);
};
 

ref de google style sheet

17voto

Matthieu M. Points 101624

Pour ajouter un peu là.

La solution traditionnelle est, comme il a été dit, de déclarer à la fois Copy Constructor et Assignment Operator comme private, et pas à définir .

  • Parce qu'ils sont private, cela conduira à une erreur de compilation de quelqu'un d'essayer de les utiliser qui n'a pas accès à la partie privée de la classe...
  • Ce qui laisse les amis (et la classe elle-même) pour laquelle l'erreur se fera sous la forme d' undefined symbol, soit à un lien en temps (si vous vérifiez pour ceux-là) ou plus probablement au moment de l'exécution (quand vous essayez de charger la bibliothèque).

Bien sûr, il est assez gênant dans le second cas, parce que vous devez ensuite vérifier votre code par vous-même puisque vous n'avez pas l'indication du fichier et la ligne à laquelle l'erreur se produit. Heureusement, elle est limitée à vos méthodes de classe et amis.


Aussi, il est intéressant de noter que ces propriétés sont transitive en bas de l'héritage et la composition de la route: le compilateur ne génère par défaut des versions de l' Default Constructor, Copy Constructor, Assignment Operator et de la Destructor si elle peut.

Cela signifie que pour un de ces quatre, ils sont générés automatiquement et seulement si ils sont accessibles pour toutes les bases et les attributs de la classe.

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

C'est pourquoi, héritant de cette classe (ou en l'utilisant comme un attribut) empêche efficacement votre propre classe pour être copiable ou cessibles, sauf si vous définissez ces opérateurs vous-même.

Généralement, l'héritage est choisi sur la composition là pour 2 raisons:

  • L'objet est efficacement Uncopyable, même si le polymorphisme ne peut être qu'utile
  • L'héritage conduit à l' EBO ou Empty Base Optimization, tandis qu'un attribut est adressable et ainsi occupera de la mémoire (dans chaque instance de la classe), même si elle n'a pas besoin de l'utiliser, le compilateur a la possibilité de ne pas ajouter cette surcharge de travail pour une classe de base.

Vous pouvez, sinon, déclarer les opérateurs privés et de ne pas les définir dans votre propre classe, mais le code sera moins auto-documentation, et vous ne serait pas en mesure de rechercher automatiquement pour ceux de la classe qui ont cette propriété, alors (sauf si vous avez un véritable analyseur).

Espérons que cela de jeter un peu de lumière sur le mécanisme.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X