Когда и почему я получаю копию при инициализации ссылки?
Есть случаи, когда я хочу ссылку на объект, но вместо этого получаю копию.
Вот пример:
std::pair<const std::string, int> foo("hello", 5);
const std::pair<std::string, int> & bar = foo;
std::cout << "foo: " << foo.first << " " << foo.second << std::endl;
std::cout << "bar: " << bar.first << " " << bar.second << std::endl;
foo.second = 7;
std::cout << "foo: " << foo.first << " " << foo.second << std::endl;
std::cout << "bar: " << bar.first << " " << bar.second << std::endl;
Это дает:
foo: hello 5
bar: hello 5
foo: hello 7
bar: hello 5
Итак, по-видимому, была создана копия foo
, в то время как синтаксис предлагает (по крайней мере, мне), что программист хотел получить ссылку на него.
Это нарушает принцип, согласно которому ссылка должна быть псевдонимом чего-то. Было бы здорово, если бы кто-нибудь мог объяснить, что происходит и почему.
(Примечание: я столкнулся с этим здесь)
Ответы
Ответ 1
Основные типы foo
и bar
различны, поэтому создается временное создание с использованием неявного преобразования из типа на RHS в одно из LHS *. Стандарт С++ позволяет привязать const
к привязке к временному и продлить его время жизни.
Ссылка const
bar
связывается с тем временным, который является отдельным объектом из foo
.
Если вы будете использовать одни и те же типы, вы получите ожидаемый результат:
std::pair<const std::string, int> foo("hello", 5);
const std::pair<const std::string, int> & bar = foo;
или
std::pair<std::string, int> foo("hello", 5);
const std::pair<std::string, int> & bar = foo;
даст
foo: hello 5
bar: hello 5
foo: hello 7
bar: hello 7
* std::pair
имеет конструктор , который допускает это неявное преобразование из одного типа пары в другой.
Ответ 2
Это специальное свойство ссылок на const
(и rreue refereneces, естественно). Эти ссылки могут связываться с временными объектами.
Обратите внимание, что std::pair<const std::string, int>
(тип foo
) отличается от std::pair<std::string, int>
(тип, к которому bar
хочет ссылаться, по модулю const
). В вашем коде нет объекта типа std::pair<std::string, int>
, поэтому bar
не может связываться с каким-либо таким объектом.
Однако, как я уже говорил, ссылки на const
и ссылки rvalue могут связываться с временными. И объект типа std::pair<std::string, int>
может быть неявно создан из объекта типа std::pair<const std::string, int>
. Следовательно, создается такой временный объект, а bar
привязан к этому временному. Это ссылочное связывание также увеличивает время жизни временного до bar
*.
Вот почему вы получаете копию. Если вы изменили тип bar
на std::pair<std::string, int> &
(т.е. Сбросили const
), вместо этого вы получите ошибку компиляции, которую ссылка не константного lvalue не может привязываться к временному.
* В специальном случае переменной-члена ссылочного типа, привязанного к временному, временное время жизни будет продолжаться только до конца конструктора, который инициализировал ссылку.