有些情况下,我想要一个对象的引用,但我得到一个副本。 这是一个例子:
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)
答案 0 :(得分:15)
foo
和bar
的基础类型不同,因此使用从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>
* 在绑定到临时的引用类型的成员变量的特殊情况下,临时的生存期只会延伸到初始化引用的构造函数的结尾。