Voir le titre.
J'ai:
class Foo {
private:
Foo();
public:
static Foo* create();
}
Que dois-je faire d'ici pour que Foo soit 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 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& ) = delete; // non construction-copyable
Foo& operator=( const Foo& ) = delete; // non copyable
public:
static Foo* create();
}
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.
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&) = delete; \
void operator=(const TypeName&) = delete
Ensuite, en classe Foo:
class Foo {
public:
Foo(int f);
~Foo();
private:
DISALLOW_COPY_AND_ASSIGN(Foo);
};
#include <boost/utility.hpp>
class Foo : boost::noncopyable {...
Mais comme l'a dit un jour Scott Meyers ... "C'est un bon cours, c'est juste que je trouve le nom un peu différent, err non naturel", ou quelque chose du genre.
Pour ajouter un peu là.
Comme on l’a dit, la solution traditionnelle consiste à déclarer les deux Copy Constructor
et Assignment Operator
sous la forme private
, et pas à définir eux.
private
, cela entraînera une erreur compile-time de la part de ceux qui essaieront de les utiliser et qui n’ont pas accès aux parties privées de la classe ...undefined symbol
, soit à link-time (si vous les recherchez), soit très probablement à run-time ( en essayant de charger la bibliothèque).Bien sûr, dans le second cas, le problème est considérable car vous devez alors vérifier votre code vous-même, car vous ne disposez pas de l'indication du fichier ni de la ligne sur laquelle l'erreur se produit. Heureusement, cela se limite à vos méthodes de cours et à vos amis.
De plus, il convient de noter que ces propriétés sont transitives sur la voie de l'héritage et de la composition: le compilateur ne générera que les versions par défaut du Default Constructor
, du Copy Constructor
, du Assignment Operator
et du Destructor
s'il le peut.
Cela signifie que pour l’un quelconque de ces quatre, ils sont automatiquement générés seulement s’ils sont accessibles pour toutes les bases et attributs de la classe.
// What does boost::noncopyable looks like >
class Uncopyable {
public:
Uncopyable() {}
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
C'est pourquoi hériter de cette classe (ou l'utiliser comme attribut) empêchera efficacement votre propre classe d'être copiée ou assignable à moins que vous ne définissiez vous-même ces opérateurs.
Généralement, l'héritage est choisi ici pour la composition pour deux raisons:
Uncopyable
, même si le polymorphisme peut ne pas être utileEBO
ou Empty Base Optimization
, alors qu'un attribut sera adressable et occupera donc de 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 ajouter cette surcharge pour une classe de base.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 self-documenting et vous ne pourriez pas rechercher automatiquement les classes qui possèdent cette propriété ( sauf si vous avez un analyseur complet).
J'espère que cela a jeté un peu de lumière sur le mécanisme.
En C++ 11, vous pouvez explicitement désactiver la création du constructeur de copie et d'assignation 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 manière typique de rendre un objet C++ non copiable est de déclarer explicitement un constructeur de copie et un opérateur d'affectation de copie, sans toutefois les implémenter. Cela empêchera le compilateur de générer le sien. (En règle générale, cela est associé à leur déclaration private
pour générer une erreur de compilation au lieu d'une erreur de l'éditeur de liens.)
Il existe également la classe boost::noncopyable
dont vous pouvez hériter, ce qui correspond à ce que j'ai décrit ci-dessus.
Rendre le constructeur de copie privé.
Foo(const Foo& src);
Vous n'avez pas besoin de l'implémenter, il suffit de le déclarer 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 est de déclarer le constructeur de copie et l'affectation supprimés publiquement . Non supprimé personnellement, publiquement supprimé: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines# Rc-delete