Как сделать этот объект C++ не подлежащим копированию?

Смотрите заголовок.

Я имею:

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

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

Спасибо!

10 ответов

Решение
class Foo {
   private:
     Foo();
     Foo( const Foo& ); // 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

РЕДАКТИРОВАТЬ: C++11 версия, если у вас есть компилятор, поддерживающий эту функцию:

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

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

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

Из Википедии:

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

То же самое касается классов, конечно.

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

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

Еще один способ запретить конструктор копирования. Для удобства можно использовать макрос 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);
};

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

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

Традиционное решение состоит в том, чтобы объявить Copy Constructor а также Assignment Operator как privateи не определять их.

  • Потому что они 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в то время как атрибут будет адресуемым и, таким образом, будет занимать память (в каждом экземпляре класса), даже если он ему фактически не нужен, у компилятора есть возможность не добавлять эти издержки для базового класса.

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

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

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

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

Хорошей практикой в ​​C++11 является объявление конструктора копирования и присваивания как публично удаленных. Не приватно удалено, публично удалено: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines

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

Foo(const Foo& src);

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

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

/* 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
{
};
Другие вопросы по тегам