Имеет ли значение возвращаемый оператор «operator =», если я хочу, чтобы класс не копировался? - PullRequest
5 голосов
/ 26 декабря 2011

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

  1. это требует дополнительных усилий, и мне не нужны эти операции в моем классе или
  2. эти операции не будут иметь смысла в моем классе

так что я хочу запретить их. Для этого я объявлю их закрытыми и не предоставлю реализацию :

class NonCopyable {
private:
   NonCopyable( const NonCopyable& ); //not implemented anywhere
   void operator=( const NonCopyable& ); //not implemented anywhere
};

Теперь я могу выбрать любой тип возврата для operator=() функции-члена. Будет ли иметь значение, какой тип возврата я выберу?

Ответы [ 5 ]

7 голосов
/ 26 декабря 2011

Нет, тип возврата не имеет значения.

Стандарт C ++ не накладывает никаких требований на тип возвращаемого значения для специальных функций-членов назначения копирования, которые вы объявляете сами. Это просто должен быть operator=(), который принимает «ровно один параметр типа X, X&, const X&, volatile X& или const volatile X&». †† Следовательно, void operator=( const NonCopyable& ); по-прежнему является оператором копирования (определенным пользователем, если быть точным).

Поскольку вы фактически указали свой собственный оператор назначения копирования, он будет превосходить генерацию оператора назначения копирования по умолчанию. Это приводит к тому, что все вызовы NonCopyable оператора копирования присваиваются вашим, в результате чего любые попытки использовать оператор назначения копирования не компилируются, так как он объявлен private.

class Foo : NonCopyable
{
};

int main()
{
    Foo a;
    Foo b;
    // Compiler complains about `operator=(const NonCopyable&)`
    // not accessible or something like that.
    a = b;
}

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


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

†† C ++ Стандарт: 12.8 Копирование объектов класса [class.copy]

9 Объявленный пользователем copy оператор присваивания X::operator= - это нестатическая не шаблонная функция-член класса X с ровно одним параметр типа X, X&, const X&, volatile X& или const volatile X&.

2 голосов
/ 26 декабря 2011

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

1 голос
/ 26 декабря 2011

Это имеет значение крошечный, крошечный бит:

  • void обеспечивает небольшой процент случайных / ошибочных вызовов (a = b = c / f (d = e)) извнутри реализации класса производят ошибки времени компиляции, а не ошибки времени компоновки, которые могут сэкономить время компиляции и быть более понятными (минимально релевантны для больших классов, к которым обращаются многие разработчики, некоторые из которых имеют ограниченное предварительное знакомство).

    void будет звонить в тревогу для меня (и, надеюсь, большинства разработчиков), задаваясь вопросом, хотите ли вы:

    • , чтобы удалить сгенерированные по умолчанию operator=
    • былипросто ленивый по поводу дополнительного набора текста, или
    • были незнакомы / небезразличны относительно обычно ожидаемой семантики operator=.

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

  • возврат ссылки на тип может сделать общую сигнатуру функции более узнаваемой, или визуальный поиск за сложным типом, чтобы найти operator=, может иметь обратный эффект - всев глазах (и уме) смотрящего ....
1 голос
/ 26 декабря 2011

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

Интересно, boost::noncopyable оператор копирования назначен для возврата const noncopyable&, но я думаю, что это просто соглашение.

1 голос
/ 26 декабря 2011

Нет, потому что вы можете вернуть что-нибудь из operator=, даже если вы определите его реализацию.

...