2009-08-27 3 views
16

В стандарте кодирования нашей компании нам сказали «знать, как можно (случайное) копирование можно предотвратить».предотвращает случайное копирование объектов в C++

Я не совсем уверен, что это значит, но предположим, что они означают, что мы должны прекращать копирование классов, если это не требуется.

Что я могу думать следующим образом:

  1. Сделать конструктор копирования класса частной.
  2. Сделать оператор присваивания (operator =) класса приватным.
  3. Сделать конструктор класса явным (чтобы остановить создание классов с использованием неправильных переменных).
  4. Для всех классов, которые выполняют распределение памяти и где требуется копирование, убедитесь, что оператор копирования и оператор присваивания выполняют глубокое копирование, а не мелкое копирование.

Есть ли я на правильном пути? Есть ли что-то, что я мог пропустить?

+0

+1. Я думаю, вы получили это прямо в своем списке :) – kkaploon

+0

На самом деле, я бы понял, что это предложение означает, что вы должны знать об этих вещах и следить за тем, чтобы вы случайно не копировали объекты, которые вам не нужны. Но что я знаю? Так или иначе, вопрос интереснее. –

ответ

9

Если ваш стандарт кодирования означает «знать о способах (случайное) копирование, можно предотвратить», я предполагаю, что они не просто говорят о предотвращении копирования из самих классов, но и о последствиях производительности ненужных/случайные копии, когда с использованием классов.

Одной из основных причин ненужной потери производительности в коде людей, новых для C++, является ненужное копирование, обычно с помощью временных рядов. Компиляторы становятся все лучше и лучше при принятии решения, когда временные периоды не нужны (см. Комментарий "Want speed? Pass by Value", благодаря комментарию Konrad), но лучше всего научиться осознавать внутреннюю работу копирования и временные файлы на C++ (среди прочих). Для меня чтение Efficient C++ действительно заставило меня начать.

+2

Ваш второй пункт во многом неправильный/вводящий в заблуждение, принимая во внимание копирование и NRVO. Чтобы позволить профессионалу говорить: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ –

+0

Это отличная статья на самом деле - я знал о RVO, но в последний раз, когда я размышлял в него я все еще использовал VS2003, и было рискованным бизнесом, чтобы зависеть от компилятора, чтобы он стал правильным для более сложных типов. Рад слышать, что это становится намного меньше проблемы с C++ 0X –

+0

@MadKeithV: не вводите в заблуждение упоминание C++ 0x: * все * в этой статье относится к текущим компиляторам и текущей версии C++, ничего не нового для C++ 0x. –

10

Если вы используете импульс, то самый простой способ предотвратить класс от копирования является, выводя свой класс от noncopyable:

#include <boost/noncopyable.hpp> 

class Foo : private boost::noncopyable 
{ 
} 

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

+0

Я не думал, что он хочет, чтобы класс был скопирован, скорее он хочет предотвратить его скопировать * случайно *. – kkaploon

+0

Я считаю, что он это делает, потому что он перечисляет как один из вариантов, делающих конструктор копирования закрытым. –

+0

Насколько мне нравится boost, я столкнулся с несколькими рабочими ситуациями, в которых это просто не разрешалось. – Greg

21

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

Взгляните на boost::noncopyable.

Update (повторно в Tal Прессман):

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

Ну, я полагаю, что любая случайно копии будет выполняться с помощью оператора присваивания либо или конструктора копирования. Поэтому сделать их частными действительно имеет смысл: если копирование объектов является дорогостоящей операцией, то копирование должно быть явным: другой разработчик может непреднамеренно косвенно вызвать copy op, и компилятор сообщит ему, что это запрещено.

+0

+1 для повышения noncopyable –

2

Вы на правильном пути. Если вы не хотите использовать boost, вы можете сделать следующее: Сделать экземпляр конструктора копирования и операцию копирования экземпляром приватным и не выполнять их. Таким образом, вы получите ошибку компилятора, если попытаетесь скопировать экземпляр.

0

Ваш список отлично смотрится с точки зрения предотвращения ошибок, например. удаляя одну и ту же область памяти более одного раза из-за общих указателей от неявного копирования объектов.

Надеюсь, это также актуально; из заявления «знать о путях (случайном) копировании можно предотвратить», вы можете принять это как «осознавать непреднамеренное ненужное копирование». Это будет означать обстоятельства, которые могут повлиять на производительность. В очень простом примере ваши кодирования конвенции может означать, что вы должны отдать предпочтение:

std::string text1("some text"); 

над:

std::string text1 = "some text"; 

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

+0

Спасибо за ваш комментарий. Это то, о чем я не знаю. Поэтому всегда вызывайте конструктор вместо использования назначения, если требуется преобразование типа. – Andy

+0

Я не уверен, что вы правы с этим. Оба создают временный символ []. –

+1

Нет, это просто неправильно. * Все современные компиляторы избегают ненужного временного экземпляра 'std :: string' в этом случае. –

0

Да, у вас что-то не хватает, может быть случай в классе, где функция-член копирует один объект в другой. Функция-член может получить доступ к конструктору частной копии или оператору присваивания.

Лучший способ сделать еще один класс ... Позволяет сказать NonCopyable, этот класс будет иметь свой конструктор копирования и оператор присваивания как закрытый, а затем сделать ваш класс, чтобы сказать MyClass подкласс класса NonCopyable.

Это ограничит создание любого объекта Myclass, поскольку для этого потребуется вызов конструктора класса NonCopyable. Кроме того, поскольку функция члена Myclass не будет иметь доступа к частным конструкторам класса NonCopyable, это также ограничивает эту ситуацию.

Также будет более элегантным создание объекта класса, не подлежащего копированию, путем наследования класса NonCopyable.