Предотвращать случайное копирование объектов в С++
В нашем стандарте кодирования нашей компании нам сказали: "Помните, как можно предотвратить (случайное) копирование".
Я не уверен, что это значит, но предположим, что они означают, что мы должны прекращать копирование классов, если это не требуется.
Я могу думать о следующем:
- Сделать конструктор копии класса закрытым.
- Сделать оператор присваивания (operator =) класса закрытым.
- Сделать конструктор класса явным (чтобы остановить создание классов с использованием неправильных переменных).
- Для всех классов, которые выполняют распределение памяти и где требуется копирование, убедитесь, что конструктор копирования и оператор присваивания выполняют глубокое копирование, а не мелкое копирование.
Я на правильном пути? Есть ли что-нибудь, что я мог пропустить?
Ответы
Ответ 1
Если ваш стандарт кодирования гласит: "Помните, как можно (случайное) копирование можно предотвратить", я предполагаю, что они не просто говорят о предотвращении копирования из самих классов, но и о последствиях производительности ненужных/случайные копии при использовании классов.
Одной из основных причин ненужной потери производительности в коде людей, новых для С++, является ненужное копирование, обычно через временные. Составители становятся все лучше и лучше при принятии решения, когда временные данные не нужны (см. "Хотите скорость? Pass by Value" , благодаря комментарию Konrad), но лучше всего научиться осознавать внутреннюю работу копирования и временные рамки на С++ (среди прочих). Для меня действительно началось чтение Efficient С++.
Ответ 2
Да, делая приватный оператор присваивания и экземпляр копирования, вы не сможете создавать какую-либо копию объекта с использованием стандартных методов (но если вам действительно нужна копия объекта, который вы можете реализовать, например, метод Copy(), который будет выполнять глубокая копия).
Взгляните на boost:: noncopyable.
Обновить (повторно для Tal Pressman):
... вы должны знать об этих вещах и следить за тем, чтобы вы случайно не копировали объекты, которые вам не нужны.
Я полагаю, что любая случайная копия будет выполнена с использованием оператора присваивания или конструктора копирования. Поэтому сделать их частными на самом деле имеет смысл: если копирование объектов является дорогостоящей операцией, то копирование должно быть явным: другой разработчик может непреднамеренно косвенно вызвать copy op, и компилятор сообщит ему, что это запрещено.
Ответ 3
Если вы используете boost, то самый простой способ предотвратить копирование класса - это вывести ваш класс из noncopyable:
#include <boost/noncopyable.hpp>
class Foo : private boost::noncopyable
{
}
Это делает ваше намерение более ясным, чем вручную, что делает конструктор копирования и оператор-ассистент частным, и он имеет тот же результат.
Ответ 4
Вы на правильном пути. Если вы не хотите использовать boost, вы можете сделать следующее: Сделать экземпляр конструктора копирования и операцию копирования экземпляром приватным и не выполнять их. Таким образом, вы получите ошибку компилятора, если попытаетесь скопировать экземпляр.
Ответ 5
Ваш список выглядит великолепно с точки зрения предотвращения ошибок, например. удаляя одну и ту же область памяти более одного раза из-за общих указателей от неявного копирования объектов.
Я надеюсь, что это также актуально; из заявления "знать о путях (случайном) копировании можно предотвратить", вы можете принять это как "осознавать непреднамеренное ненужное копирование". Это будет означать обстоятельства, которые могут повлиять на производительность. В очень простом примере ваши правила кодирования могут означать, что вы должны предпочесть:
std::string text1( "some text" );
над
std::string text1 = "some text";
Второй случай может привести к временной строке создается для хранения "текста" до того, как оператор присваивания вызывается (форма копирования) для заполнения text1 с "каким-то текстом". Очевидно, что это тривиальный пример, и хорошая практика диктует, что вы должны использовать инициализацию конструктора (первый пример), где это возможно.
Ответ 6
Да, вы ничего не заметили, может быть случай в классе, где функция-член копирует один объект в другой.
Функция-член может обращаться к конструктору частной копии или оператору присваивания.
Лучший способ сделать еще один класс.... позволяет говорить NonCopyable, этот класс будет иметь свой конструктор копирования и оператор присваивания как закрытый, а затем сделать ваш класс, чтобы сказать MyClass подкласс класса NonCopyable.
Это ограничит создание любого объекта Myclass, поскольку для этого потребуется вызов конструктора класса NonCopyable. Кроме того, поскольку функция члена Myclass не будет иметь доступа к частным конструкторам класса NonCopyable, это также ограничивает эту ситуацию.
Также будет более элегантно сделать объект класса не подлежащим копированию, наследуя класс NonCopyable.