C ++, почему оператор присваивания должен возвращать const ref, чтобы избежать (a = b) = c - PullRequest
23 голосов
/ 16 января 2011

Я читаю книгу о C ++, а точнее о перегрузке операторов.

Пример следующий:

const Array &Array::operator=(const Array &right)
{
// check self-assignment
// if not self- assignment do the copying
return *this; //enables x=y=z
}

Объяснение, представленное в книге о возврате const ref вместо ref, состоит в том, чтобы избежать присвоений, таких как (x = y) = z. Я не понимаю, почему мы должны избегать этого. Я понимаю, что x = y вычисляется первым в этом примере, и поскольку он возвращает константную ссылку, часть = z не может быть выполнена. Но почему?

Ответы [ 5 ]

26 голосов
/ 16 января 2011

(x=y) означает x.operator=(y), что возвращает объект x.Следовательно, (x=y)=z означает (x.operator=(y)).operator=(z).Выражение в скобках устанавливает x в y и возвращает x, а затем внешний бит устанавливает x в z.Он не устанавливает y в z, как вы могли бы ожидать, и как это делает выражение x = y = z.

Это поведение нелогично (все они должны быть равны после назначения, верно?);возврат константной ссылки делает это невозможным и позволяет избежать проблемы.

20 голосов
/ 16 января 2011

Нет необходимости избегать этого, если только книга не предназначена для программистов, которые обычно пишут (x=y)=z, когда они означают x=y=z.На практике никто в здравом уме не пишет об этом, поэтому меры предосторожности совершенно не нужны.Он также запрещает некоторые другие краткие конструкции, такие как (x=y).nonConstMember(), которые вряд ли кто-нибудь напишет, но это может быть полезно в некоторых контекстах (хотя их не следует чрезмерно использовать).лучшая книга.

12 голосов
/ 16 января 2011

Насколько я знаю, операторы присваивания не возвращают константные ссылки в идиоматическом C ++.Стандартные типы также не возвращают константные ссылки.

std::string a, b, c;
(a = b).clear(); // no objection from compiler

Все мои пользовательские операторы присваивания вернули неконстантную ссылку.

В случае сомнений проверьте библиотеку Standard.Он не безупречен, но он определенно получает правильные базовые вещи.

3 голосов
/ 16 января 2011

Я бы посмотрел на поведение встроенных типов.

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

Итак, если мы посмотрим на целые числа:

int main()
{
    int x = 5;
    int y = 6;
    int z = 7;

    (x = y) = z;
    std::cout << x << " " << y << " " << z << "\n";
}

Это работает при неизменном y и назначении x 7. В вашем коде я бы ожидал, что ваш оператор присваивания будет работать так же. Стандартное определение оператора присваивания:

Array& Array::operator=(Array const& rhs)
{
    /* STUFF */
    return *this;
}

Должен делать это очень хорошо (при условии, что / * STUFF * / правильный).

1 голос
/ 16 января 2011

Единственная причина, которую я вижу, состоит в том, что эта книга была написана для объяснения C ++ программистам C (или автором, чье понимание C лучше, чем понимание C ++).Потому что для программиста на C выражение (x = y) = z недопустимо для встроенных типов, и он, вероятно, попытается получить то же поведение с его пользовательскими типами.

Однако C и C ++ отличаютсяязыки, а в C ++ выражение (x = y) = z допустимо даже для встроенных типов.Поэтому, если вы хотите иметь такое же поведение для ваших пользовательских типов, вы должны вернуть неконстантную ссылку в operator =.

. Я бы посоветовал вам получить лучшую книгу, которая несделать путаницу между C и C ++.Это не те же самые языки, даже если они происходят от общей основы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...