Вимкнути конструктор копій


173

У мене клас:

class SymbolIndexer {
protected:
  SymbolIndexer ( ) { }

public:
  static inline SymbolIndexer & GetUniqueInstance ( ) 
  { 
    static SymbolIndexer uniqueinstance_ ;
    return uniqueinstance_ ; 
  }
};

Як я можу змінити його, щоб відключити код, наприклад:

SymbolIndexer symbol_indexer_ = SymbolIndexer::GetUniqueInstance ( );

і дозволяти лише такий код, як:

SymbolIndexer & ref_symbol_indexer_ = SymbolIndexer::GetUniqueInstance ( );

1
До речі, це сингл з умовами успадкування (з захистом)?
Р. Мартіньо Фернандес

Я маю сумніви у вашому коді щоразу, коли буде створено інший примірник, я думаю, що GetUniqueInstance () завжди посилатиметься на один і той же об’єкт.
Пратем Шах

Відповіді:


286

Ви можете зробити конструктор копій приватним і не забезпечити його реалізацію:

private:
    SymbolIndexer(const SymbolIndexer&);

Або в C ++ 11 прямо заборонити це:

SymbolIndexer(const SymbolIndexer&) = delete;

43
Щодо deleteключового слова, я хочу додати наступне. Моя нинішня звичка при розробці нового класу - це deleteяк конструктор копій, так і оператор присвоєння негайно. Я виявив, що залежно від контексту вони здебільшого непотрібні, а їх видалення запобігає випадкам несподіваної поведінки. Якщо виникла ситуація, коли може знадобитися копіюючий копій, визначте, чи це можна зробити за допомогою семантики переміщення. Якщо це небажано, надайте реалізацію як (!) Копіювальному пристрою, так і оператору призначення. Чи це гарний підхід, я залишу читачеві.
pauluss86

1
@ pauluss86 Мені подобається ваш підхід, але я б не повністю його дотримувався, оскільки, думаю, час, витрачений за цією схемою, більший, ніж час, збережений помилками, які він запобігає. Я просто забороняю копіювати, коли не впевнений.
Томаш Зато - Відновіть Моніку

@ pauluss86 Це в основному те, що робить Rust: Переміщення за замовчуванням (і const за замовчуванням). Дуже корисно на мій погляд.
Капічу

33

Якщо ви не заперечуєте проти багатократного успадкування (зрештою, це не так вже й погано), ви можете написати простий клас із приватним конструктором копій та оператором присвоєння та додатково підкласифікувати його:

class NonAssignable {
private:
    NonAssignable(NonAssignable const&);
    NonAssignable& operator=(NonAssignable const&);
public:
    NonAssignable() {}
};

class SymbolIndexer: public Indexer, public NonAssignable {
};

Для GCC це дає таке повідомлення про помилку:

test.h: In copy constructor ‘SymbolIndexer::SymbolIndexer(const SymbolIndexer&)’:
test.h: error: ‘NonAssignable::NonAssignable(const NonAssignable&)’ is private

Я не дуже впевнений, щоб це працювало в кожному компіляторі. Існує відповідне запитання , але поки немає відповіді.

UPD:

В C ++ 11 ви також можете написати NonAssignableклас наступним чином:

class NonAssignable {
public:
    NonAssignable(NonAssignable const&) = delete;
    NonAssignable& operator=(NonAssignable const&) = delete;
    NonAssignable() {}
};

У deleteЗапобігає ключових слів членів від того по замовчуванням зведених, тому вони не можуть бути використані в подальшому , за замовчуванням , побудованих членів Похідний класу. Спроба призначити дає наступну помилку в GCC:

test.cpp: error: use of deleted function
          ‘SymbolIndexer& SymbolIndexer::operator=(const SymbolIndexer&)’
test.cpp: note: ‘SymbolIndexer& SymbolIndexer::operator=(const SymbolIndexer&)’
          is implicitly deleted because the default definition would
          be ill-formed:

UPD:

У Boost вже є клас саме з тією ж метою, я думаю, він навіть реалізований аналогічно. Клас викликається boost::noncopyableі має на увазі використовуватись у наступному:

#include <boost/core/noncopyable.hpp>

class SymbolIndexer: public Indexer, private boost::noncopyable {
};

Я рекомендую дотримуватися рішення Boost, якщо ваша проектна політика дозволяє. Дивіться також ще одне boost::noncopyableпов'язане питання для отримання додаткової інформації.


Чи не повинно це бути NonAssignable(const NonAssignable &other);?
Тройсеф

Я думаю, що це питання отримало би більше результатів, якби воно було оновлено до deleteсинтаксису ключових слів C ++ 11 .
Томаш Зато - Відновіть Моніку

@ TomášZato: Ідея полягає в тому, щоб конструктор копій та оператор присвоєння були присутніми, але приватними. Якщо ви deleteїх, він перестане працювати (я щойно перевірив).
firegurafiku

@ TomášZato: Ах, вибачте, мій метод тестування трохи помилявся. Видалення творів теж. Відповідь буде оновлено через хвилину.
firegurafiku

3
@Troyseph: const Class&і Class const&майже однакові. Для покажчиків у вас може бути рівний Class const * constтип.
firegurafiku

4

Зробити SymbolIndexer( const SymbolIndexer& )приватним. Якщо ви присвоюєте посилання, ви не копіюєте.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.