在初始化参考时何时以及为什么要获得副本?

Sar*_*ien 13 c++ reference

有些情况下,我想要一个对象的引用,但我得到一个副本.这是一个例子:

  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;
Run Code Online (Sandbox Code Playgroud)

这会产生:

foo: hello 5
bar: hello 5
foo: hello 7
bar: hello 5
Run Code Online (Sandbox Code Playgroud)

所以显然foo已经创建了一个副本,而语法建议(至少对我来说)程序员想要引用它.这违反了引用应该是某种东西的别名的原则.如果有人能够解释发生了什么以及为什么会这样,那将是很棒的.

(注意:我在这里遇到过这个)

jua*_*nza 15

底层类型foobar不同,因此使用从RHS上的类型到LHS *上的类型的隐式转换创建临时.C++标准允许const引用绑定到临时并延长其生命周期.

const参考bar结合该临时,这是从一个不同的对象foo.

如果你使用相同的类型,你会得到你期望的结果:

std::pair<const std::string, int> foo("hello", 5);
const std::pair<const std::string, int> & bar = foo;
Run Code Online (Sandbox Code Playgroud)

要么

std::pair<std::string, int> foo("hello", 5);
const std::pair<std::string, int> & bar = foo;
Run Code Online (Sandbox Code Playgroud)

会屈服

foo: hello 5
bar: hello 5
foo: hello 7
bar: hello 7
Run Code Online (Sandbox Code Playgroud)

*std::pair有一个模板构造函数,允许从一种类型的对到另一种类型的隐式转换.

  • 为了强调`bar`为同一类型的例子,你可以使用`const auto&bar = foo;`.这是关键字的目的,以防止不必要的隐式转换. (2认同)

Rei*_*ica 5

这是引用const(以及rvalue refereneces,自然)的特殊属性.这些引用可以绑定到临时对象.

请注意std::pair<const std::string, int>(类型foo)是一种不同的类型std::pair<std::string, int>(bar想要引用的类型,模数const).std::pair<std::string, int>代码中没有类型对象,因此bar无法绑定到任何此类对象.

但是,正如我所说,引用const和右值引用可以绑定到临时对象.并且std::pair<std::string, int>可以从类型的对象隐式地创建类型的对象std::pair<const std::string, int>.因此,创建了这样的临时对象,并bar绑定到该临时对象.此引用绑定还将临时的生命周期延长到bar*的生命周期.

这就是你得到副本的原因.如果你改变的类型barstd::pair<std::string, int> &(即放弃了const),你会得到,而不是一个编译错误,一个非const左值引用不能绑定到一个暂时的.


*在绑定到临时的引用类型的成员变量的特殊情况下,临时的生存期将仅延伸到初始化引用的构造函数的结尾.