2015-02-11 3 views
1

Теперь это очень концептуально. Я не знаю, правильно ли я это понимаю, поэтому, пожалуйста, помогите мне понять разницу.'const string & getName() const {}' vs 'string getName() const {}'?

Давайте предположим, что name является частным членом std::string данных, доступ к которым с помощью функции getName() аксессора:

const string& getName() const { 
     return name; 
} 

Итак, это возвращает ссылку, которая просто другое слово для псевдонима, чтобы name. Таким образом, возвращается псевдоним, то есть возвращается элемент данных name. Разрешено ли это или будет ли оно уничтожить всю цель скрытия данных?

Другими словами, как именно вышеуказанный способ отличается от обычного:

string getName() const { 
    return name; 
} 

???

И, наконец, действительно ли стоит реализовать прежний, а не последний?

+0

Нельзя. [[[[[[[[[[[[[[[[[[[ –

+0

] Что вы пытаетесь сказать? – abcde

+0

Один экземпляр и его ссылка –

ответ

-1

Возврат ссылки на константу лучше, так как она не делает копию строки. Причина, по которой я говорю это, заключается в том, что интерфейс более гибкий таким образом - вы всегда можете скопировать ссылку const в другую строку, если это необходимо, или вы можете использовать ее в качестве ссылки - до вызывающего. Возврат члена по значению, и вы всегда застреваете с копией. Если name большой или используется часто, это повлияет на производительность, и я предполагаю, что производительность - одна из причин, по которой вы используете C++.

Теперь другие ответы поднимают некоторые отрицательные моменты о возврате ссылки const, которая, как я считаю, недействительна.

Забота о том, что вы можете отбросить const, действительна, но исключение const является лишь одним из инструментов инструментария разработчика C++. Зачем убирать? Если кто-то действительно хочет возиться с вашим объектом, он всегда может сделать это на C++, обратившись к памяти напрямую, поэтому создание кода для сохранения ваших абонентов от самих себя бессмысленно. Кастинг сотника const показывает намерение сделать это, и, на мой взгляд, все в порядке. Это означает, что у вызывающего есть некоторые очень специфические причины для этого и знает, что const, который отбрасывается, предназначен для неконстантного объекта и, следовательно, является безопасным.

Учебный пример в другом ответе просто глуп:

const string s& = foo().name(); 

Опять же, создав код, чтобы попытаться сохранить вызывающий от себя ограничивают вас от силы C++. Если бы кто-то действительно хотел бы сделать вышеизложенное, то был бы правильный способ:

string s = foo().name(); 

Так что этот вопрос тоже спорный.

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

Что вы действительно должны спросить себя, так это, что такое обычный случай использования name()?

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

Для меня тот факт, что он называется name, подразумевает, что он будет использоваться в основном для печати/регистрации и сравнения.Таким образом, ссылка const является явным победителем здесь.

Также посмотрите на руководство по стилю. Большинство из них проведут вас по ссылке const и возвращают элементы по ссылке const. Есть очень веские причины сделать это, как описано выше.

+0

Теперь я понимаю. – abcde

+0

«лучше» - это вопрос мнения, каждая версия имеет свои плюсы и минусы. Существуют и другие соображения, кроме того, делается ли копия. Он также может зависеть от наиболее распространенного варианта использования объекта. –

+0

@MattMcNabb. Правда, я отредактировал свой ответ с лучшим объяснением ... нет каламбуры;) – Rado

1

Первый позволяет вызывающим абонентам некоторый прямой доступ к вашей внутренней переменной имени. Конечно, он постоянный, поэтому на него можно только вызвать методы const. Но все же вы хотите, чтобы внешние абоненты работали на ваших скрытых внутренних данных? Хуже того, что, если какой-то bozo решает const_cast использовать внутренний буфер данных строки и взламывать его?

Вторая возвращает копию вашей внутренней переменной имени. Совершенно безопасно для любых абонентов.

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

3

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

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

Более академичная проблема заключается в том, что она может сломать код, если раньше была возвратная стоимость, или просто потому, что это необычно. Например.

const string s& = foo().name(); 

С foo() возвращением объекта по значению, и name() возвращает строку по ссылке, это дает вам оборванную ссылку вместо наивного ожидаемой продолжительной жизни. Я называю это академическим, потому что я не могу представить, чтобы кто-то писал это. Тем не менее, закон Мерфи и все такое.

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

Итак:

  • , вероятно, не значительно более эффективным,

  • предотвращает изменение реализации легко,

  • также имеет академическую проблему, получая висячие ссылки.

В сумме просто не надо.

Это преждевременная оптимизация и усложнение.

+0

* Это, вероятно, не будет более эффективным, чем возврат стоимости, именно потому, что маловероятно, что он используется только для инициализации ссылки * - я категорически не согласен с это. Тот факт, что он называется 'name', подразумевает, что он, скорее всего, будет использоваться для сравнения, печати/ведения журнала, в качестве ключа на карте и т. Д. Большинство из них ** будет более эффективным. Теперь ваш академический пример просто подталкивает его ... все, что вам нужно сделать, это 'string s =', и ваша проблема исчезает, и она становится как (in) эффективной, как решение для оценки. – Rado

+0

@Rado: Давайте изменим мое заявление на «значительно более эффективное». Используя словарь из 58112 слов в нижнем регистре, просматривая слово «быстро» 1 миллион раз на 'std :: map ', с MinGW g ++ 4.9.1 и '-O2', я получил (как типичный пример) 0.117085 секунд, прошедших для значения-возвращения и 0.109069 секунд, прошедших с возвратом. С Visual C++ 13.0 и '/ O2' я получил 0.218411 секунд, прошедших для значений-возвращает 0.200394 секунд, прошедших для возврата. ИМХО, это очень маргинальная оптимизация, абсолютно не стоит. Код на странице (http://codepad.org/n7rkUc9T). –

Смежные вопросы