Цель возврата по константному значению?

Какова цель const в этом?

const Object myFunc(){
    return myObject;
}

Я только начал читать «Эффективный C++», и пункт 3 поддерживает это, а поиск в Google находит похожие предложения, но также и контрпримеры. Я не понимаю, как использование const здесь было бы предпочтительнее. Предполагая, что возврат по значению желателен, я не вижу причин защищать возвращаемое значение. Пример, приведенный для того, почему это может быть полезно, - это предотвращение непреднамеренного логического приведения возвращаемого значения. Реальная проблема заключается в том, что неявное приведение типа bool должно быть предотвращено с помощью ключевого слова manifest.

Использование const здесь предотвращает использование временных объектов без назначения. Поэтому я не мог выполнять арифметические выражения с этими объектами. Не похоже, чтобы когда-либо была полезна безымянная константа.

Что дает здесь использование const и когда это предпочтительнее?

РЕДАКТИРОВАТЬ: измените арифметический пример на любую функцию, которая изменяет объект, который вы, возможно, захотите выполнить перед назначением.


person Praxeolitic    schedule 03.01.2012    source источник
comment
Да, вы можете выполнять арифметические действия с константными объектами, потому что арифметические операторы должны быть константными и также возвращать константные объекты.   -  person Seth Carnegie    schedule 03.01.2012


Ответы (4)


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

(a + b).expensive();

Однако в эпоху C++11 настоятельно рекомендуется возвращать значения как неконстантные, чтобы вы могли в полной мере использовать ссылки rvalue, которые имеют смысл только для непостоянных rvalue.

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

person Kerrek SB    schedule 03.01.2012
comment
Итак, Херб Саттер рекомендуется возвращать константные значения для непримитивных типов, но я думаю, вы правы, что этот совет сейчас устарел. - person Fred Larson; 03.01.2012
comment
@FredLarson: Да, в книге 14-летней давности :-S - person Kerrek SB; 18.08.2014
comment
Этот ответ подразумевает, что возврат по константному значению означает const &&, но так ли это на самом деле?! например VS13 позволяет мне связать int&& var= с функцией, которая возвращает const int. Результатом вызова функции, возвращаемый тип которой не является ссылкой, является значение prvalue. - person Karlis Olte; 01.06.2015
comment
@ user64985: Я не совсем понимаю, к чему вы клоните. prvalue - это rvalue. - person Kerrek SB; 01.06.2015
comment
Я задала вопрос. Эта цитата была единственной соответствующей информацией, которую я смог найти в стандарте, и в ней не упоминается const. - person Karlis Olte; 01.06.2015
comment
Но я предполагаю, что они действительно const&&, поскольку мой компилятор не позволяет делать то же самое с типами классов. Я предполагаю, что компилятор просто хорош с целыми числами. - person Karlis Olte; 01.06.2015
comment
Итак, @KerrekSB, совет Херба Саттера все еще действителен для C++ 98/C++ 03? - person stephanmg; 08.06.2020

Это красиво бессмысленно для вернуть значение const из функции.

сложно заставить это как-то повлиять на ваш код:

const int foo() {
   return 3;
}

int main() {
   int x = foo();  // copies happily
   x = 4;
}

и:

const int foo() {
   return 3;
}

int main() {
   foo() = 4;  // not valid anyway for built-in types
}

// error: lvalue required as left operand of assignment

Хотя вы можете заметить, что тип возвращаемого значения определяется пользователем:

struct T {};

const T foo() {
   return T();
}

int main() {
   foo() = T();
}

// error: passing ‘const T’ as ‘this’ argument of ‘T& T::operator=(const T&)’ discards qualifiers

сомнительно, что это кому-то выгодно.

Возврат ссылки отличается, но если Object не является параметром шаблона, вы этого не делаете.

person Lightness Races in Orbit    schedule 03.01.2012
comment
Обратите внимание, что второй пример вызывает ошибку только для встроенных типов. - person Xeo; 03.01.2012
comment
Можно поподробнее о первом примере? Мне не имеет смысла говорить, что возвращаемое значение будет константным, но иметь возможность присвоить его неконстантной переменной. - person Ivaylo Toskov; 09.02.2015
comment
@IvayloToskov: Все подробности, которые вам нужны, находятся в примере, особенно в комментарии, в котором говорится, что копируется успешно. Рассмотрим const int x = 4; int y = x;, что тоже прекрасно. - person Lightness Races in Orbit; 09.02.2015
comment
@LightnessRacesinOrbit: Вау, дыра в стандарте. Должна быть возможность создать объект, который нельзя скопировать, прочитать или обновить. Для малых значений x = 4. - person ; 14.07.2015
comment
@nocomprende: Почему? Какая от этого польза? - person Lightness Races in Orbit; 14.07.2015
comment
@LightnessRacesinOrbit: ответ ниже описывает тип, который нельзя копировать, только перемещать. Мой вопрос был таким же, как ваш. - person ; 14.07.2015
comment
@nocomprende: я не могу найти ни одной области на этой странице, в которой вы задали вопрос. - person Lightness Races in Orbit; 14.07.2015
comment
@LightnessRacesinOrbit: это ответ Никола Боласа. Моя точка зрения заключалась в том, что стандарты, кажется, допускают снежную бурю совершенно бессмысленных (для меня) случаев, которые служат только пищей для аргументов. Мы должны были придерживаться более простого языка и дать бедным компиляторам передышку. - person ; 14.07.2015
comment
@nocomprende: Ваш ник забавно подходит, так как я понятия не имею, о чем вы говорите. - person Lightness Races in Orbit; 14.07.2015
comment
Что, если метод возвращает константный контейнер, а вызывающая сторона использует его в range-for? Без константы будет вызываться begin()/end(), а с константой — cbegin()/cend(). В мире Qt, где неконстантное начало стоит дорого (может отсоединиться из-за копирования при записи), это имеет значение. Обычная альтернатива — поместить контейнер в локальную переменную const, а затем использовать ее в range-for, но это раздражающий обходной путь. Поэтому мне интересно, действительно ли возврат const-контейнера не является допустимой задачей... (хотя, конечно, вызывающая сторона может сделать неконстантную копию, я это знаю). - person David Faure; 14.09.2019
comment
@DavidFaure Конечно, это звучит как хорошая причина сделать это. - person Lightness Races in Orbit; 14.09.2019
comment
@LightnessRacesinOrbit на самом деле оказывается, что мы оба ошибаемся. Я разговаривал с главой команды разработчиков llvm/clang, и он сказал мне, что возврат значения const на самом деле не имеет никакого эффекта. т.е. в моем примере выше он по-прежнему будет вызывать неконстантные методы begin() и end(). Мы должны думать об этом как о локальной копии, константа теряется. Он планирует подать документ в комитет C++, чтобы объявить устаревшими константные аргументы и константные возвращаемые значения для функций (константа только верхнего уровня, const-ref по-прежнему подходит). - person David Faure; 21.09.2019
comment
@DavidFaure Так не должно быть; это не соответствует требованиям, и я никогда не был свидетелем этого. Что касается отказа от аргументов const, это звучит глупо: они уже игнорируются в объявлениях и хороши и полезны в определениях. - person Lightness Races in Orbit; 21.09.2019
comment
Ургх, вы правы, тестовый пример показывает, что const действительно имеет значение. davidfaure.fr/kde/const_retval.cpp выводит для меня const begin. Я напишу ему. И да, идея состояла в том, чтобы отказаться от аргументов const только в объявлениях, а не в определениях. - person David Faure; 22.09.2019

Это гарантирует, что возвращаемый объект (который в этот момент является RValue) не может быть изменен. Это гарантирует, что пользователь не может думать следующим образом:

myFunc() = Object(...);

Это бы хорошо работало, если бы myFunc возвращалось по ссылке, но почти наверняка является ошибкой, когда возвращается по значению (и, вероятно, не будет обнаружено компилятором). Конечно, в C++11 с его rvalue это соглашение не имеет такого большого смысла, как раньше, поскольку константный объект нельзя переместить, так что это может сильно повлиять на производительность.

person Grizzly    schedule 03.01.2012
comment
Это не объясняет const. - person Nicol Bolas; 03.01.2012
comment
@Nicol Bolas: Как это не объясняет константу? Пример кода при компиляции, если возвращаемый тип Object, но не const Object - person Grizzly; 03.01.2012
comment
Предположительно, вы имеете в виду C++11 с его xvalues? (Знаем, что xvalues и prvalues являются rvalues, но xvalues являются новыми для C++. 11, которые являются важным отличием.) - person CB Bailey; 03.01.2012

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

Хотя любой оптимизатор, скорее всего, все равно оптимизирует его...

person Steven Feldman    schedule 03.01.2012
comment
Нечего оптимизировать, константность — это механизм безопасности во время компиляции. - person Paul Manta; 03.01.2012
comment
Кажется, вместо этого вы думали о возврате постоянной ссылки, так что это не имеет значения. И, вероятно, это следует сделать, возвращая копию значения любого типа указателя/итератора дозорного узла, нет необходимости возвращать какую-либо ссылку, если только копирование не дорого. И если бы возвращалось значение, не было бы необходимости/точки для создания этого const, так что полный круг. - person underscore_d; 10.07.2020