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

时间:2015-01-26 13:18:36

标签: 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;

这会产生:

foo: hello 5
bar: hello 5
foo: hello 7
bar: hello 5

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

(注意:我遇到了这个here

2 个答案:

答案 0 :(得分: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;

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有一个template constructor,允许从一种类型的对转换到另一种类型。

答案 1 :(得分: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和rvalue引用的引用可以绑定到临时对象。并且可以从类型为std::pair<std::string, int>的对象隐式创建类型为std::pair<const std::string, int>的对象。因此,创建了这样的临时对象,bar绑定到该临时对象。此引用绑定还将临时的生命周期延长到bar * 的生命周期。

这就是你得到副本的原因。如果您将bar的类型更改为std::pair<std::string, int> &(即删除了const),则会出现编译错误,即非常量左值引用无法绑定到临时值。< / p>


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