Как сделать этот объект С++ не скопированным?

См. главу.

У меня есть:

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

Что мне нужно сделать, чтобы сделать Foo не скопированным?

Спасибо!

Ответ 1

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

Если вы используете boost, вы также можете наследовать от noncopyable: http://www.boost.org/doc/libs/1_41_0/boost/noncopyable.hpp

EDIT: версия С++ 11, если у вас есть компилятор, поддерживающий эту функцию:

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

Ответ 2

Сделайте конструктор копирования и оператор присваивания приватным. Просто объявления достаточно, вам не нужно предоставлять реализацию.

Ответ 3

Еще один способ запретить конструктор копирования. Для удобства можно использовать макрос DISALLOW_COPY_AND_ASSIGN:

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

Тогда в классе Foo:

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

 private:
  DISALLOW_COPY_AND_ASSIGN(Foo);
};

ref из таблицы стилей Google

Ответ 4

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

Но как однажды сказал Скотт Майерс: "Это классный класс, просто я нахожу имя немного un, err non natural" или что-то в этом роде.

Ответ 5

Чтобы добавить немного туда.

Традиционное решение, как уже было сказано, объявляет как Copy Constructor, так и Assignment Operator как private, а не - define.

  • Поскольку они private, это приведет к ошибке времени компиляции от любого, кто пытается использовать их, у которых нет доступа к частным частям класса...
  • Что оставляет друзей (и сам класс), для которых ошибка будет возникать в форме undefined symbol, либо во время ссылки (если вы проверяете их там), либо, скорее всего, во время выполнения (при попытке загрузите библиотеку).

Конечно, во втором случае это довольно беспокоит, потому что вам нужно сначала проверить свой код, так как у вас нет указателя на файл и строку, в которой происходит ошибка. К счастью, он ограничивается вашими методами и друзьями.


Кроме того, стоит отметить, что эти свойства транзитивны по пути наследования и композиции: компилятор будет генерировать только версии Default Constructor, Copy Constructor, Assignment Operator и Destructor по умолчанию, если это может.

Это означает, что для любого из четырех они автоматически генерируются только, если они доступны для всех баз и атрибутов класса.

// What does boost::noncopyable looks like >
class Uncopyable {
public:
  Uncopyable() {}

private:
  Uncopyable(const Uncopyable&);
  Uncopyable& operator=(const Uncopyable&);
};

Вот почему наследование этого класса (или использование его как атрибута) эффективно предотвратит копирование или назначение вашего собственного класса, если вы сами не определите эти операторы.

Обычно наследование выбирается по составу по двум причинам:

  • Объект эффективно Uncopyable, даже если полиморфизм может быть не таким полезным
  • Наследование приводит к EBO или Empty Base Optimization, тогда как атрибут будет адресуемым и, таким образом, будет занимать память (в каждом экземпляре класса), даже если он на самом деле не нужен, компилятор имеет возможность не добавлять это служебные данные для базового класса.

Вы также можете объявить операторы частными и не определять их в своем собственном классе, но код будет менее самодокументированным, и вы не сможете автоматически искать те классы, у которых есть это свойство (если у вас полноразмерный парсер).

Надеюсь, что это пролило некоторый свет на механизм.

Ответ 6

В С++ 11 вы можете явно отключить создание конструктора копирования и назначения по умолчанию, разместив = delete после объявления.

От Wikipedia:

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

То же самое относится и к классам.

Ответ 7

Типичный способ сделать объект С++ не копируемый - явно объявить конструктор копирования и оператор присваивания копии, но не реализовать их. Это предотвратит создание компилятором собственного. (Обычно это делается в сочетании с объявлением их private, чтобы он генерировал ошибку компиляции вместо ошибки компоновщика.)

Также существует класс boost::noncopyable, который вы можете наследовать, что делает то, что я описал выше.

Ответ 8

Сделать конструктор копирования закрытым.

Foo(const Foo& src);

Вам не нужно его реализовывать, просто объявите его в файле заголовка.

Ответ 9

Это то, что я использую:

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

В вашем случае:

struct Example : NoCopy
{
};