Тип возвращаемого значения изменен с const Bar& getBar() на const Bar getBar().
Если я использую:
const auto& bar = getBar();
и тип возвращаемого значения изменится. У меня есть ссылка на временный объект.
Если я использую:
const auto bar = getBar();
я всегда делаю копию Bar.
Какова наилучшая практика для этой проблемы?
class Bar {
public:
Bar() = default;
Bar(const Bar&) = default;
Bar(Bar&&) = delete;
Bar& operator=(const Bar&) = delete;
Bar& operator=(const Bar&&) = delete;
void setValue(int i);
int value() const;
private:
int m_i = 0;
};
class Foo {
public:
Foo(Bar& bar) : m_bar(bar) {}
Foo(const Foo&) = delete;
Foo(Foo&&) = delete;
Foo& operator=(const Foo&) = delete;
Foo& operator=(const Foo&&) = delete;
const Bar& giveMeBar();
private:
Bar& m_bar;
};
int main() {
auto bar = std::make_unique<Bar>();
auto foo = std::make_unique<Foo>(*bar.get());
const auto& barFromFoo = foo->giveMeBar();
bar->setValue(2);
std::cout << "original bar: " << bar->value() << std::endl;
std::cout << "bar from foo: " << barFromFoo.value() << std::endl;
}
В показанном коде нет getBar().
как вы думаете, почему auto актуален? const Bar& barFromFoo = foo->giveMeBar(); vs Bar barFromFoo = foo->giveMeBar(); точно такая же история
auto — это просто вывод типа. Это не утиная типизация, это строгая типизация (через выведенный тип). Вы хотели бы auto const& получить константную ссылку, или auto& получить ссылку, или auto&& получить ссылку-или-константную ссылку, в зависимости от ситуации. Или просто auto чтобы получить отдельный экземпляр. Или auto const чтобы получить отдельную копию, то есть const.
Какова наилучшая практика для решения этой проблемы? Мои коллеги, которые много знают об этом, говорят, что отдают предпочтение семантике значений. Возврат по значению. Передача по значению. Склонность в пользу API неизменяемых объектов, а не API изменяемых объектов.
Лучше всего узнать, нужен ли вам псевдоним, или скопировать и ввести auto& или auto в зависимости от этого. Другая лучшая практика — когда интерфейс того, что вы использовали, изменился, вы поддерживаете свой код в соответствии с изменениями.
Я написал ответ, но на самом деле я не совсем уверен, что вы называете «проблемой». Как вы думаете, что-то не так с выводом текущих кодов? Или с выводом кода после изменения типа возвращаемого значения?
Несвязано, но const для возвращаемого типа по значению вряд ли будет полезен. Единственное, что он делает, это не позволяет писать что-то вроде getBar()->setValue(1). Если возвращаемое значение хранится в переменной, то const вообще не имеет значения, и имеет значение только const переменной.





То, что на самом деле является «лучшей практикой», основано на мнениях. Я лишь попытаюсь объяснить, почему ваша предпосылка неверна, чтобы вы могли сами составить свое мнение о том, что является хорошей практикой, и/или оценить некоторые рекомендации по этому вопросу.
Если я использую:
const auto& bar = getBar();и тип возвращаемого значения изменится. У меня есть ссылка на временный объект.
Время жизни временного объекта продлевается и привязывается к постоянной ссылке. Нет проблем. Если вы хотите избежать ненужного копирования, не делайте копии. В показанном коде вы можете без проблем заменить const Bar& giveMeBar(); на const Bar giveMeBar();.
Для иллюстрации рассмотрим этот пример:
#include <iostream>
struct foo {
~foo(){ std::cout << "yes. I leave now. Bye\n";}
};
foo bar() { return foo{};}
int main() {
const foo& f = bar();
std::cout << "are you still there?\n";
}
Вывод :
are you still there?
yes. I leave now. Bye
PS: auto в этом ничего не меняет. Следующие выражения попарно эквивалентны:
const auto& barFromFoo = foo->giveMeBar();
const Bar& barFromFoo = foo->giveMeBar(); // same
// and
const auto barFromFoo = foo->giveMeBar();
const Bar barFromFoo = foo->giveMeBar(); // same
Нет, у вас не будет ссылки на временный объект, как на объект, который немедленно уничтожается. Вы будете удивлены, узнав, что получите ссылку на «несколько» временный объект, который будет существовать до тех пор, пока не закончится его область действия. Что касается кодекса по своему охвату, то он будет таким же постоянным, как и сама земная твердь.