0

我是 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;    

输出是“Hello World”。

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

4

4 回答 4

2

你所做的是赋值s2s1refToS仍然是指代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
于 2013-09-13T10:17:23.037 回答
0
refToS = s2;  // make reference point to object 2

这条线没有做你认为它做的事情。在这就像一个任务s2发生s1

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

于 2013-09-13T10:17:44.230 回答
0

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

refToS = s2;

不做你认为它做的事。它实际上将 分配s2给什么refToS引用(即`s1)。所以,这条线实际上是这样做的:

s1 = s2;

并且在它被执行之后,两者都s2s1等于“世界”

于 2013-09-13T10:17:44.433 回答
0

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

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

C++ 标准有以下规则:

如果在一个对象的生命周期结束之后并且在对象占用的存储空间被重用或释放之前,在原始对象占用的存储位置创建一个新对象,一个指向原始对象的指针,一个指向原始对象的引用引用原始对象,或者原始对象的名称将自动引用新对象,并且一旦新对象的生命周期开始,可用于操作新对象,如果:

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

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

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

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

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

显然,说“引用是对象”是一种误解。这个陈述在概念上是错误的另一个证明是当对象超出范围时,析构函数运行。当引用超出范围时,什么都不会发生。引用是在初始化期间绑定到内存位置的句柄(就像const指针一样),并且作为句柄,它与对象本身不同。

于 2017-05-17T17:19:09.450 回答