Объявление ссылки на объект и оператор присваивания

Я чувствую, что этот вопрос достаточно важен, чтобы быть где-то там, но я не могу найти ответа на него.

Предположим, что у меня есть этот код:

//class member function
std::map< std::string, std::string > myMap;

const std::map< std::string, std::string >& bar()
{
   return myMap;
}

void myFunc( std::map< std::string, std::string >& foo1 )
{
   foo1 = bar();
   std::map< std::string, std::string >& foo2 = bar();
}

Я понимаю, что если я начну использовать foo2, так как foo2 является ссылкой на тот же экземпляр, что и возвращаемый bar(), все, что я делаю с foo2, будет отражено в myMap. Но как насчет foo1? Получает ли foo1 копию myMap или он также указывает на тот же экземпляр, что и bar()? Стандартная библиотека С++ говорит, что оператор присваивания для std:: map скопирует элементы, но тогда означает ли это, что оператор присваивания действительно не вызывается в объявлении foo2?

Спасибо!

Ответ 1

Ссылки не переустанавливаются в С++. Это означает, что после их инициализации вы не сможете переназначить их. Вместо этого любое присвоение фактически включает упомянутый объект. Итак, в вашем коде

foo1 = bar();
std::map< std::string, std::string >& foo2 = bar();

первая строка вызывает std::map::operator= объекта, который был передан как параметр myFunc. После этого foo1 неподвижные объекты ссылаются на тот же объект, но его значение (например, какие элементы, которые он содержит) может быть очень хорошо изменено.

Обратите внимание, что вторая строка не является присвоением, если есть какие-либо сомнения в том, что это было в вашем уме. Вместо этого это инициализация. Так как тип возврата бара на самом деле std::map<std::string, std::string> const&, он не может привязываться к std::map<std::string, std::string>&, поэтому он компилирует ошибку.


Чтобы расширить "философскую" сторону вещей, ссылки на С++ разработаны настолько, насколько это возможно, и не существуют как объекты. Это использует значение термина С++ Standard (оно не связано с ООП): это означает, что, например, ссылочные типы не имеют размера. Вместо этого sizeof(T&) == sizeof(T). Аналогично, ссылки не имеют адресов, и невозможно сформировать указатель или ссылку на ссылку: данный int& ref = i;, затем &ref == &i.

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

Ответ 2

Линия

foo1 = bar();

создает копию (потому что это оператор присваивания map).