为什么引用不能在 C++ 中重新安装
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/728233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why are references not reseatable in C++
提问by TheFogger
C++ references have two properties:
C++ 引用有两个属性:
- They always point to the same object.
- They can not be 0.
- 它们总是指向同一个对象。
- 它们不能为 0。
Pointers are the opposite:
指针正好相反:
- They can point to different objects.
- They can be 0.
- 它们可以指向不同的对象。
- 它们可以是 0。
Why is there no "non-nullable, reseatable reference or pointer" in C++? I can't think of a good reason why references shouldn't be reseatable.
为什么在 C++ 中没有“不可为空、可重置的引用或指针”?我想不出一个很好的理由为什么引用不应该被重新安装。
Edit:The question comes up often because I usually use references when I want to make sure that an "association" (I'm avoiding the words "reference" or "pointer" here) is never invalid.
编辑:这个问题经常出现,因为当我想确保“关联”(我在这里避免使用“引用”或“指针”这个词)永远不会无效时,我通常会使用引用。
I don't think I ever thought "great that this ref always refers to the same object". If references were reseatable, one could still get the current behavior like this:
我认为我从来没有想过“这个 ref 总是指同一个对象,这很棒”。如果引用是可重新安装的,人们仍然可以获得这样的当前行为:
int i = 3;
int& const j = i;
This is already legal C++, but meaningless.
这已经是合法的 C++,但毫无意义。
I restate my question like this:"What was the rationale behind the 'a reference isthe object' design? Why was it considered useful to have references alwaysbe the same object, instead of only when declared as const?"
我这样重申我的问题:“'引用就是对象'设计背后的基本原理是什么?为什么引用总是同一个对象而不是仅在声明为 const 时被认为是有用的?”
Cheers, Felix
干杯,菲利克斯
回答by Michael Burr
The reason that C++ does not allow you to rebind references is given in Stroustrup's "Design and Evolution of C++" :
C++ 不允许您重新绑定引用的原因在 Stroustrup 的“C++ 的设计和演化”中给出:
It is not possible to change what a reference refers to after initialization. That is, once a C++ reference is initialized it cannot be made to refer to a different object later; it cannot be re-bound. I had in the past been bitten by Algol68 references where
r1=r2
can either assign throughr1
to the object referred to or assign a new reference value tor1
(re-bindingr1
) depending on the type ofr2
. I wanted to avoid such problems in C++.
初始化后无法更改引用所指的内容。也就是说,一旦 C++ 引用被初始化,以后就不能再引用不同的对象;它不能重新绑定。我在过去由Algol68的引用,其中被咬伤
r1=r2
可以通过分配r1
给对象称为或分配新的基准值,以r1
(再结合r1
),取决于类型r2
。我想在 C++ 中避免这样的问题。
回答by rlbond
In C++, it is often said that "the reference isthe object". In one sense, it is true: though references are handled as pointers when the source code is compiled, the reference is intended to signify an object that is not copied when a function is called. Since references are not directly addressable (for example, references have no address, & returns the address of the object), it would not semantically make sense to reassign them. Moreover, C++ already has pointers, which handles the semantics of re-setting.
在 C++ 中,常说“引用即对象”。从某种意义上说,这是正确的:尽管在编译源代码时引用作为指针处理,但引用旨在表示在调用函数时未复制的对象。由于引用不能直接寻址(例如,引用没有地址,& 返回对象的地址),重新分配它们在语义上没有意义。此外,C++ 已经有了处理重新设置语义的指针。
回答by jalf
Because then you'd have no reseatable type which can not be 0. Unless, you included 3 types of references/pointers. Which would just complicate the language for very little gain (And then why not add the 4th type too? Non-reseatable reference which can be 0?)
因为那样你就没有不能为 0 的可重置类型。除非你包含了 3 种类型的引用/指针。这只会使语言复杂化以获得很少的收益(然后为什么不也添加第 4 种类型?不可重新安装的引用,它可以是 0?)
A better question may be, why would you want references to be reseatable? If they were, that would make them less useful in a lot of situations. It would make it harder for the compiler to do alias analysis.
一个更好的问题可能是,为什么您希望引用可重新安装?如果是这样,那将使它们在很多情况下变得不那么有用。这会使编译器更难进行别名分析。
It seems that the main reason references in Java or C# are reseatable is because they do the work of pointers. They point to objects. They are not aliases for an object.
似乎 Java 或 C# 中的引用可重新安装的主要原因是因为它们完成了指针的工作。它们指向对象。它们不是对象的别名。
What should the effect of the following be?
下面的效果应该是什么?
int i = 42;
int& j = i;
j = 43;
In C++ today, with non-reseatable references, it is simple. j is an alias for i, and i ends up with the value 43.
在今天的 C++ 中,使用不可重新安装的引用,这很简单。j 是 i 的别名,而 i 的值是 43。
If references had been reseatable, then the third line would bind the reference j to a different value. It would no longer alias i, but instead the integer literal 43 (which isn't valid, of course). Or perhaps a simpler (or at least syntactically valid) example:
如果引用是可重置的,那么第三行会将引用 j 绑定到不同的值。它不再是 i 的别名,而是整数文字 43(当然,这是无效的)。或者也许是一个更简单(或至少在语法上有效)的示例:
int i = 42;
int k = 43;
int& j = i;
j = k;
With reseatable references. j would point to k after evaluating this code. With C++'s non-reseatable references, j still points to i, and i is assigned the value 43.
带有可重新安装的参考。j 将在评估此代码后指向 k。对于 C++ 的不可重置引用,j 仍然指向 i,而 i 被赋值为 43。
Making references reseatable changes the semantics of the language. The reference can no longer be an alias for another variable. Instead it becomes a separate type of value, with its own assignment operator. And then one of the most common usages of references would be impossible. And nothing would be gained in exchange. The newly gained functionality for references already existed in the form of pointers. So now we'd have two ways to do the same thing, and no way to do what references in the current C++ language do.
使引用可重坐会改变语言的语义。引用不能再是另一个变量的别名。相反,它变成了一种单独的值类型,具有自己的赋值运算符。然后引用的最常见用法之一将是不可能的。并且不会得到任何交换。新获得的引用功能已经以指针的形式存在。所以现在我们有两种方法可以做同样的事情,而无法做当前 C++ 语言中的引用所做的事情。
回答by Brian R. Bondy
A reference is not a pointer, it may be implemented as a pointer in the background, but its core concept is not equivalent to a pointer. A reference should be looked at like it *is*
the object it is referring to. Therefore you cannot change it, and it cannot be NULL.
引用不是指针,它可能在后台实现为指针,但其核心概念并不等同于指针。一个引用应该像它所引用*is*
的对象一样看待。因此你不能改变它,它不能为 NULL。
A pointer is simply a variable that holds a memory address. The pointer itself has a memory address of its own, and inside that memory address it holds another memory addressthat it is said to point to. A reference is not the same, it does not have an address of its own, and hence it cannot be changed to "hold" another address.
指针只是一个保存内存地址的变量。 指针本身有一个自己的内存地址,在该内存地址中,它保存着另一个据说指向的内存地址。 引用不一样,它没有自己的地址,因此不能更改为“持有”另一个地址。
I think the parashift C++ FAQ on referencessays it best:
我认为参考资料上的parashift C++ FAQ说得最好:
Important note: Even though a reference is often implemented using an address in the underlying assembly language, please do not think of a reference as a funny looking pointer to an object. A reference is the object. It is not a pointer to the object, nor a copy of the object. It is the object.
重要提示:尽管引用通常是使用底层汇编语言中的地址实现的,但请不要将引用视为指向对象的有趣指针。引用是对象。它不是指向对象的指针,也不是对象的副本。它是对象。
and again in FAQ 8.5:
再次在FAQ 8.5 中:
Unlike a pointer, once a reference is bound to an object, it can not be "reseated" to another object. The reference itself isn't an object (it has no identity; taking the address of a reference gives you the address of the referent; remember: the reference is its referent).
与指针不同,一旦引用绑定到一个对象,它就不能“重新定位”到另一个对象。引用本身不是一个对象(它没有身份;获取引用的地址会给你所指的地址;记住:引用是它的所指)。
回答by j_random_hacker
A reseatable reference would be functionally identical to a pointer.
可重置引用在功能上与指针相同。
Concerning nullability: you cannot guarantee that such a "reseatable reference" is non-NULL at compile time, so any such test would have to take place at runtime. You could achieve this yourself by writing a smart pointer-style class template that throws an exception when initialised or assigned NULL:
关于可空性:您不能保证这样的“可重坐引用”在编译时是非空的,因此任何此类测试都必须在运行时进行。您可以通过编写一个智能指针样式的类模板来实现这一点,该模板在初始化或分配为 NULL 时抛出异常:
struct null_pointer_exception { ... };
template<typename T>
struct non_null_pointer {
// No default ctor as it could only sensibly produce a NULL pointer
non_null_pointer(T* p) : _p(p) { die_if_null(); }
non_null_pointer(non_null_pointer const& nnp) : _p(nnp._p) {}
non_null_pointer& operator=(T* p) { _p = p; die_if_null(); }
non_null_pointer& operator=(non_null_pointer const& nnp) { _p = nnp._p; }
T& operator*() { return *_p; }
T const& operator*() const { return *_p; }
T* operator->() { return _p; }
// Allow implicit conversion to T* for convenience
operator T*() const { return _p; }
// You also need to implement operators for +, -, +=, -=, ++, --
private:
T* _p;
void die_if_null() const {
if (!_p) { throw null_pointer_exception(); }
}
};
This might be useful on occasion -- a function taking a non_null_pointer<int>
parameter certainly communicates more information to the caller than does a function taking int*
.
这在某些情况下可能很有用—— 一个带non_null_pointer<int>
参数的函数肯定比一个带参数的函数传递给调用者更多的信息int*
。
回答by snemarch
It would probably have been less confusing to name C++ references "aliases"? As others have mentioned, references in C++ should be though of asthe variablethey refer to, not as a pointer/referenceto the variable. As such, I can't think of a good reason they shouldbe resettable.
将 C++ 引用命名为“别名”可能不会那么混乱?正如其他人所提到的,C++ 中的引用应该被视为它们所引用的变量,而不是变量的指针/引用。因此,我不能想到一个很好的理由,他们应该是复位。
when dealing with pointers, it often makes sense allowing null as a value (and otherwise, you probably want a reference instead). If you specifically want to disallow holding null, you could always code your own smart pointer type ;)
在处理指针时,允许 null 作为值通常是有意义的(否则,您可能需要一个引用)。如果您特别想禁止持有空值,您可以随时编写自己的智能指针类型;)
回答by dhaumann
Intrestingly, many answers here are a bit fuzzy or even beside the point (e.g. it's not because references cannot be zero or similar, in fact, you can easily construct an example where a reference is zero).
有趣的是,这里的许多答案都有些模糊甚至离题(例如,这不是因为引用不能为零或相似,事实上,您可以轻松构建一个引用为零的示例)。
The real reason why re-setting a reference is not possible is rather simple.
无法重新设置参考的真正原因相当简单。
Pointers enable you to do two things: To change the value behind the pointer (either through the
->
or the*
operator), and to change the pointer itself (direct assign=
). Example:int a; int * p = &a;
- Changing the value requires dereferencing:
*p = 42;
- Changing the pointer:
p = 0;
- Changing the value requires dereferencing:
References allow you to only change the value. Why? Since there is no other syntax to express the re-set. Example:
int a = 10; int b = 20; int & r = a; r = b; // re-set r to b, or set a to 20?
指针使您可以做两件事:更改指针后面的值(通过
->
或*
运算符),以及更改指针本身(直接赋值=
)。例子:int a; int * p = &a;
- 更改值需要取消引用:
*p = 42;
- 改变指针:
p = 0;
- 更改值需要取消引用:
引用允许您只更改值。为什么?由于没有其他语法来表达重新设置。例子:
int a = 10; int b = 20; int & r = a; r = b; // re-set r to b, or set a to 20?
In other words, it would be ambiguous if you were allowed to re-set a reference. It makes even more sense when passing by reference:
换句话说,如果你被允许重新设置一个引用,那将是模棱两可的。通过引用传递时更有意义:
void foo(int & r)
{
int b = 20;
r = b; // re-set r to a? or set a to 20?
}
void main()
{
int a = 10;
foo(a);
}
Hope that helps :-)
希望有帮助:-)
回答by Mr Fooz
C++ references can sometimes be forced to be0 with some compilers(it's just a bad idea to do so*, and it violates the standard*).
C++ 引用有时会被某些编译器强制为0 (这样做是个坏主意*,而且它违反了标准*)。
int &x = *((int*)0); // Illegal but some compilers accept it
EDIT:according to various people who know the standard much better than myself, the above code produces "undefined behavior". In at least some versions of GCC and Visual Studio, I've seen this do the expected thing: the equivalent of setting a pointer to NULL (and causes a NULL pointer exception when accessed).
编辑:根据比我更了解标准的各种人,上面的代码产生了“未定义的行为”。至少在 GCC 和 Visual Studio 的某些版本中,我已经看到这做了预期的事情:相当于将指针设置为 NULL(并在访问时导致 NULL 指针异常)。
回答by Earth Engine
This is not actually an answer, but a workaround for this limitation.
这实际上不是答案,而是针对此限制的解决方法。
Basically, when you try to "rebind" a reference you are actually trying to use the same name to refer to a new value in the following context. In C++, this can be achieve by introducing a block scope.
基本上,当您尝试“重新绑定”一个引用时,您实际上是在尝试使用相同的名称来引用以下上下文中的新值。在 C++ 中,这可以通过引入块作用域来实现。
In jalf's example
在jalf的例子中
int i = 42;
int k = 43;
int& j = i;
//change i, or change j?
j = k;
if you want to change i, write it as above. However, if you want to change the meaning of j
to mean k
, you can do this:
如果你想改变i,就按上面写。但是,如果您想将 的含义更改j
为 mean k
,您可以这样做:
int i = 42;
int k = 43;
int& j = i;
//change i, or change j?
//change j!
{
int& j = k;
//do what ever with j's new meaning
}
回答by John Dibling
You can't do this:
你不能这样做:
int theInt = 0;
int& refToTheInt = theInt;
int otherInt = 42;
refToTheInt = otherInt;
...for the same reason why secondInt and firstInt don't have the same value here:
...出于同样的原因,为什么 secondInt 和 firstInt 在这里没有相同的值:
int firstInt = 1;
int secondInt = 2;
secondInt = firstInt;
firstInt = 3;
assert( firstInt != secondInt );