Какой самый надежный способ запретить конструктор копирования в C ++? - PullRequest
21 голосов
/ 18 апреля 2011

Иногда необходимо запретить конструктор копирования в классе C ++, чтобы этот класс стал «не копируемым». Конечно, operator= должен быть запрещен одновременно.

Пока что я видел два способа сделать это. Способ 1 - объявить метод закрытым и не предоставлять ему реализацию:

class Class {
//useful stuff, then
private:
    Class( const Class& ); //not implemented anywhere
    void operator=( const Class& ); //not implemented anywhere
};

Способ 2 - объявить метод закрытым и дать ему «пустую» реализацию:

class Class {
//useful stuff, then
private:
    Class( const Class& ) {}
    void operator=( const Class& ) {}
};

IMO первый лучше - даже если есть какая-то неожиданная причина, которая приводит к вызову конструктора копирования из той же функции-члена класса, позже будет ошибка компоновщика. Во втором случае этот сценарий останется незамеченным до времени выполнения.

Есть ли серьезные недостатки в первом методе? Какой способ лучше и почему?

Ответы [ 6 ]

27 голосов
/ 18 апреля 2011

Первый лучше

Еще лучше C ++ 0x ключевое слово "delete" :

class Class {
// useful stuff, then
public:
    Class(const Class&) = delete;
    void operator=(const Class&) = delete;
};
16 голосов
/ 18 апреля 2011

Первый метод заключается в том, как Boost решает его ( исходный код ), насколько я знаю, недостатков нет.На самом деле, ошибки компоновщика являются большим преимуществом этого метода.Вы хотите, чтобы ошибки возникали во время компоновки, а не когда ваш клиент выполняет ваш код, и он внезапно падает.

Если вы используете Boost, вы можете сэкономить при печати.Это так же, как ваш первый пример:

#include <boost/utility.hpp>

class Class : boost::noncopyable {
// Stuff here
}
7 голосов
/ 18 апреля 2011

Вы всегда можете унаследовать от boost::noncopyable.

В противном случае я никогда не видел причину, по которой номер 2 лучше, чем номер 1, поскольку он позволяет вам «копировать конструкцию» объекта в методы друга или классадаже при том, что это фактически не создаст истинную копию объекта.

3 голосов
/ 18 апреля 2011

Поскольку другие ответы предполагают что-то другое, и на самом деле не пытаются ответить на вопрос, вот моя попытка:

Так какой подход лучше?Это зависит от того, как вы определяете запретить копирование ?

Если вы хотите запретить копирование другим пользователям (только классам и функциям, не являющимся друзьями), а друзьям и функциям-членам можно копировать, тогда второй подход - это путь.

Если вы хотите запретить копирование всем (друзьям, не-друзьям, функциям-членам), то единственным подходящим решением является первый подход.

Обратите внимание, что второй подход не запрещает копировать друзей и функции-члены (то есть вызывать функции копирования) . 1

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

2 голосов
/ 18 апреля 2011

В вашем первом подходе нет недостатка, я использовал его для создания «не копируемого» класса.

1 голос
/ 09 ноября 2011

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

Если вы вообще не хотите, чтобы он был копируемым, как вы сказали, он выдаст ошибку компоновщика. Однако, если вы используете второй подход и в конечном итоге используете конструктор копирования случайно, он скомпилируется и запустится; и у вас не будет абсолютно никаких признаков того, откуда возникло несоответствие, пока вы не откроете отладчик. Или, как сказал Се, если вы можете использовать современный компилятор, используйте нотацию «= delete» в C ++ 11.

...