Hoe maak ik dit C++-object niet-kopieerbaar?

Zie titel.

Ik heb:

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

Wat moet ik vanaf hier doen om Foo kopieerbaar te maken?

Bedankt!


Antwoord 1, autoriteit 100%

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

Als je boost gebruikt, kun je ook overnemen van noncopyable: http://www.boost.org/doc/libs/1_41_0/boost/noncopyable.hpp

EDIT: C++11-versie als je een compiler hebt die deze functie ondersteunt:

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

Houd er rekening mee dat verwijderde methoden openbaar moeten zijn: https://isocpp.github.io/ CppCoreGuidelines/CppCoreGuidelines#Rc-delete


Antwoord 2, autoriteit 27%

Maak de kopieerconstructor en de toewijzingsoperator ook privé. Alleen de aangifte is voldoende, u hoeft geen implementatie aan te leveren.


Antwoord 3, autoriteit 19%

#include <boost/utility.hpp>
class Foo : boost::noncopyable {...

Maar zoals Scott Meyers ooit zei… “Het is een mooie klas, alleen vind ik de naam een ​​beetje on, err niet natuurlijk”, of iets dergelijks.


Antwoord 4, autoriteit 19%

In C++11 kunt u het aanmaken van een standaard kopieer- en toewijzingsconstructor expliciet uitschakelen door = deletena de declaratie te plaatsen.

Van Wikipedia:

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

Hetzelfde geldt natuurlijk voor lessen.


Antwoord 5, autoriteit 18%

Gewoon een andere manier om de kopieerconstructor niet toe te staan. Voor het gemak kan een DISALLOW_COPY_AND_ASSIGN-macro worden gebruikt:

// 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

Dan, in de klas Foo:

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

referentie van google stylesheet


Antwoord 6, autoriteit 17%

Om daar wat toe te voegen.

De traditionele oplossing is, zoals gezegd, om declarerenzowel Copy Constructorals Assignment Operatorals private, en nietom ze te definiëren.

  • Omdat ze privatezijn, leidt dit tot een compileerfoutvan iedereen die ze probeert te gebruiken en die geen toegang heeft tot de privégedeelten van de klas.. .
  • Waardoor vrienden (en de klas zelf) achterblijven waarvoor de fout zal optreden in de vorm van undefined symbol, hetzij op link-time(als u controleert op die daar) of hoogstwaarschijnlijk tijdens run-time(wanneer u de bibliotheek probeert te laden).

Natuurlijk is het in het tweede geval nogal lastig omdat je dan zelf je code moet controleren omdat je niet de aanduiding hebt van het bestand en de regel waar de fout optreedt. Gelukkig is het beperkt tot je klasmethoden en vrienden.


Het is ook vermeldenswaard dat deze eigenschappen transitief zijn langs de weg van overerving en samenstelling: de compiler genereert alleen standaardversies van de Default Constructor, de Copy Constructor, de Assignment Operatoren de Destructorindien mogelijk.

Dit betekent dat voor elk van deze vier ze automatisch alleenworden gegenereerd als ze toegankelijk zijn voor alle bases en attributen van de klasse.

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

Dit is de reden waarom het erven van deze klasse (of het gebruiken als een attribuut) effectief voorkomt dat je eigen klasse kopieerbaar of toewijsbaar is, tenzij je die operators zelf definieert.

Over het algemeen wordt er om 2 redenen gekozen voor overerving boven samenstelling:

  • Het object is in feite Uncopyable, zelfs als polymorfisme niet zo handig is
  • Overerving leidt tot EBOof Empty Base Optimization, terwijl een attribuut adresseerbaar zal zijn en dus geheugen in beslag zal nemen (in elk exemplaar van de klasse), zelfs als dat niet het geval is het echt nodig heeft, heeft de compiler de mogelijkheid om deze overhead niet toe te voegen voor een basisklasse.

U kunt ook de operators privé verklaren en ze niet in uw eigen klasse definiëren, maar de code zou minder zelfdocumenterendzijn, en u zou niet automatisch naar die klasse kunnen zoeken die deze eigenschap dan hebben (tenzij je een volledige parser hebt).

Ik hoop dat dit enig licht werpt op het mechanisme.


Antwoord 7, autoriteit 5%

De typische manier om een ​​C++-object niet-kopieerbaar te maken, is door expliciet een kopieerconstructor en kopieertoewijzingsoperator te declareren, maar deze niet te implementeren. Dit voorkomt dat de compiler zijn eigen genereert. (Meestal wordt dit gedaan in combinatie met het privatedeclareren zodat het een compilatiefout genereert in plaats van een linkerfout.)

Er is ook de boost::noncopyableklasse die je kunt erven, die doet wat ik hierboven heb beschreven.


Antwoord 8, autoriteit 4%

De goede gewoonte in C++11 is om de kopie-constructor en toewijzing als openbaar verwijderd te verklaren.
Niet privé verwijderd, openbaarverwijderd: https://isocpp. github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-delete


Antwoord 9, autoriteit 3%

Maak de kopieerconstructor privé.

Foo(const Foo& src);

Je hoeft het niet te implementeren, maar declareer het gewoon in het headerbestand.


Antwoord 10, autoriteit 2%

Dit is wat ik gebruik:

/* 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;

In jouw geval:

struct Example : NoCopy
{
};

Other episodes