Подтвердить что ты не робот

Когда и почему я получаю копию при инициализации ссылки?

Есть случаи, когда я хочу ссылку на объект, но вместо этого получаю копию. Вот пример:

  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, в то время как синтаксис предлагает (по крайней мере, мне), что программист хотел получить ссылку на него. Это нарушает принцип, согласно которому ссылка должна быть псевдонимом чего-то. Было бы здорово, если бы кто-нибудь мог объяснить, что происходит и почему.

(Примечание: я столкнулся с этим здесь)

4b9b3361

Ответ 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 не может привязываться к временному.


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