Почему возвращаемое значение должно быть const для не встроенных типов, а не const для встроенных типов?

Решения 4 и 5 на GotW #6 Const-Correctness упоминают это:

Point GetPoint( const int i ) {
    return points_[i];
}

Возврат по значению обычно должен быть константным для не встроенных типов возврата.


int GetNumPoints() {
    return points_.size();
}

.. поскольку int уже является r-значением, и введение в него "const" может помешать созданию экземпляра шаблона и вводит в заблуждение, вводит в заблуждение и, вероятно, приводит к ожирению.

У меня есть следующие вопросы

  1. Какому экземпляру шаблона мы здесь мешаем?!
  2. Что именно вводит в заблуждение здесь и почему?
  3. Почему это различие между не встроенными и встроенными. Я думал, что это плохая практика!

2 ответа

Return-by-value should normally be const for non-builtin return types ..

Это не правильно - одна из относительно немногих ошибок в GotW. const Значения были сомнительными в C++03 и определенно очень плохими в C++11.

Проблема в том, что в C++03 у rvalues ​​может быть любая вызываемая функция-член, даже неконстантная. Это замечательно, потому что вы можете "swaptimize" или выполнять цепочки методов и другие вещи, которые совершенно хороши и имеют абсолютный смысл, но это также плохо, потому что компилятор не может поймать вас, когда вы делаете что-то глупое, например, присваивание ему или что-то еще, Как правило, плохая идея ограничивать всех от хороших дел, потому что вызывающий может сделать что-то глупое. Намерение это хорошо, но это не правильно.

В C++ 11 это исправлено, потому что вы можете запретить функции-члены вызываться по rvalue, и, во-вторых, потому что для правильной работы семантики перемещения значение rvalue должно быть изменяемым. Вы не можете взять ресурсы из rvalue, если это const,

Как примечание, причина этого в том, что у примитивных типов всегда была встроенная специальная формулировка, которая делала, например, присвоение rvalues ​​незаконным, поэтому не нужно было пытаться применять это самостоятельно, делая это const,

Что касается шаблонов, я на самом деле не уверен. Уже было известно, что эта практика была плохой, когда я начал программировать на C++, поэтому мне никогда не приходилось сталкиваться с этим.

Лично я не согласен с рекомендацией ставить const на возвращаемом значении, не зависящем от семантики перемещения: значение уже является r-значением, и в результате нет большой опасности его случайного изменения. Это часть того, почему поставить const на не встроенных типах: они могут содержать своего рода бэкдор к значению. Например, std::vector<T> имеет swap() метод, который можно использовать для "кражи" содержимого неконстантного значения:

std::vector<int> f();
std::vector<int> value;
f().swap(value);

Точно так же у потоков есть некоторые операторы-члены, которые позволяют вам использовать их с некоторыми встроенными функциями, которые эффективно извлекают ссылку из потока, например:

std::string word;
std::istringstream("hello, world") >> std::skipws >> word;

Без std::skipws поток является значением, которое не может быть связано с первым аргументом std::operator>> (std::istream&, std::string&) но использование оператора-члена для манипуляторов возвращает неконстантную ссылку на поток.

const на встроенные типы фактически не влияет вообще. В частности, при передаче результата функции в шаблон функции (в C++2003) он не может различить const или неconst возвращение передается. В результате может показаться, что const оказывает влияние на встроенный возврат, хотя на самом деле это не так.

Как я уже сказал, я не согласен с правилом, и в C++2011 оно определенно не выполняется, потому что вы хотите иметь возможность в любом случае отключить не встроенное, что было бы предотвращено const вернуть.

Другие вопросы по тегам