有些情况下,我想要一个对象的引用,但我得到一个副本.这是一个例子:
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
底层类型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;
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有一个模板构造函数,允许从一种类型的对到另一种类型的隐式转换.
这是引用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*的生命周期.
这就是你得到副本的原因.如果你改变的类型bar来std::pair<std::string, int> &(即放弃了const),你会得到,而不是一个编译错误,一个非const左值引用不能绑定到一个暂时的.
*在绑定到临时的引用类型的成员变量的特殊情况下,临时的生存期将仅延伸到初始化引用的构造函数的结尾.