我对这个引用指向两个不同对象的想法有什么问题

What is wrong about my idea of this reference pointing to two different objects?

本文关键字:对象 问题 什么 引用 两个      更新时间:2023-10-16

我是C++新手,我正在努力解决经常发现的语句(例如在 http://yosefk.com/c++fqa/ref.html#fqa-8.1 中),与指针相反,初始化后您无法将引用点设置为另一个对象。

我这里有一个代码片段,在我看来,它正是这样做的:

std::string s1("Hello");
std::string s2("World");
std::string& refToS = s1;  // initialize reference to object 1
cout << refToS << endl;
refToS = s2;               // make reference point to object 2
cout << refToS << endl;    

输出为"你好世界"。

这可能是一个沉闷的问题,但我无法弄清楚我的误解是什么。

您所做的是将s2分配给s1refToS仍然引用s1

std::string s1("Hello");
std::string s2("World");
std::string& refToS = s1;  // initialize reference to object 1
cout << refToS << endl;
refToS = s2;               // assign s2 to the referent of refToS
cout << refToS << endl;    
cout << s1 << endl;
cout << s2 << endl;

输出为

Hello
World
World
World
refToS = s2;  // make reference point to object 2

这条线没有做你认为它做的事情。这就像发生了s2s1的分配。

不能更改引用指向的对象。

引用它引用的对象。所以这段代码:

refToS = s2;

不做你认为它做的事情。它实际上将s2分配给refToS引用的内容(即's1)。所以,这一行实际上是这样做的:

s1 = s2;

执行后,s2s1都将等于"世界"

虽然 John 正确地解释了您实际上是在s1上调用 string::operator=(const string&),更改s1不重新绑定引用,但我认为重要的是要指出 FQA 在这里是错误的。

可以将引用指向不同的对象,该对象在创建引用时甚至不存在。

C++标准具有以下规则:

如果在对象的生存期结束后,在重新使用或释放该对象所占用的存储之前,将在原始对象占用的存储位置创建一个新对象,则指针 指向原始对象、引用原始对象的引用或原始对象的名称将自动引用新对象,并且一旦新对象的生存期开始,就可以 用于操作新对象,如果:

  • 新对象的存储恰好覆盖原始对象占用的存储位置, 和
  • 新对象与原始对象的类型相同(忽略顶级 CV 限定符),并且
  • 原始对象的类型不是常量限定的
  • ,如果是类类型,则不包含任何类型为常量限定或引用类型的非静态数据成员,并且
  • 原始对象是类型为 T 的最派生对象,新对象是类型为 T 的最派生对象(即,它们不是基类子对象)。

用简单的英语来说,这意味着引用绑定到特定的内存位置,并且不能重新绑定到另一个内存位置。 但是该内存位置上的对象可以更改(一个对象的结束生存期,另一个对象的开始生存期),以便同一引用可以访问多个不同的对象。

为此,请使用显式析构函数调用(结束对象的生命周期,但释放内存),然后使用 placement-new:

refToS.~string();
// refToS now refers to raw storage
new (&refToS) std::string("Creating a new string");

这与在s1上使用赋值运算符不同,结果是一个全新的std::string对象。

显然,说"引用是对象"是一种误解。 此语句在概念上错误的另一个证据是,当对象超出范围时,析构函数将运行。 当引用超出范围时,不会发生任何操作。 引用是在初始化期间绑定到内存位置的句柄(就像const指针一样),作为一个句柄,它与对象本身是不同的东西。