悬挂引用和未定义的行为 [英] Dangling references and undefined behavior

查看:488
本文介绍了悬挂引用和未定义的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设悬挂引用 x 。是不确定的行为只是写

Assume a dangling reference x. Is it undefined behavior to just write

&x;

或甚至

x;

推荐答案

什么使得无效对象(引用,指针等)的使用未定义的行为是lvalue-to-rvalue转换(§4.1):

What makes the use of an invalid object (reference, pointer, whatever) undefined behaviour is lvalue-to-rvalue conversion (§4.1):


如果glvalue引用的对象不是类型T的对象,并且不是从T派生的类型的对象,或者如果对象未初始化,则需要此转换的程序具有未定义的行为。

If the object to which the glvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior.

假设我们没有重载 operator& ,一元& 运算符将一个左值作为其操作数,因此不会发生转换。只有一个标识符,如 x; 也不需要转换。当引用用作表达式中的操作数(期望操作数为右值)时,您将只能获得未定义的行为 - 这是大多数运算符的情况。关键是,& x 实际上不需要访问 x 的值。对于需要访问其值的操作符,需要进行Lvalue-to-Rvalue转换。

Assuming we haven't overloaded operator&, the unary & operator takes an lvalue as its operand, so no conversion occurs. Having just an identifier, as in x; also requires no conversion. You will only get undefined behaviour when the reference is used as an operand in an expression that expects that operand to be an rvalue - which is the case for most operators. The point is, doing &x doesn't actually require accessing the value of x. Lvalue-to-rvalue conversion occurs with those operators that need to access its value.

我相信你的代码是很好定义的。

I believe your code is well defined.

运算符& 已重载时,表达式& x 被转换为函数调用,不遵守内置运算符的规则 - 而是遵循函数调用的规则。对于& x ,函数调用的转换结果为 x.operator&() operator&(x)。在第一种情况下,当使用类成员访问运算符时,将在 x 上进行左值到右值转换。在第二种情况下, operator& 的参数将被复制初始化为 x (如 T arg = x ),其行为取决于参数的类型。例如,在参数是一个左值引用的情况下,没有未定义的行为,因为没有发生左值到右值的转换。

When operator& has been overloaded, the expression &x is transformed into a function call and does not obey the rules of the built-in operators - instead it follows the rules of a function call. For &x, the translation to function call results in either x.operator&() or operator&(x). In the first case, lvalue-to-rvalue conversion will occur on x when the class member access operator is used. In the second case, the argument of operator& will be copy-initialised with x (as in T arg = x), and the behaviour of this depends on the type of the argument. For example, in the case of the argument being an lvalue reference, there is no undefined behaviour because lvalue-to-rvalue conversion does not occur.

所以如果 operator& 对于 x 的类型重载,代码可能会或可能不会很好定义,这取决于调用运算符& 函数。

So if operator& is overloaded for the type of x, the code may or may not be well-defined, depending on the calling of the operator& function.

您可以认为一元& 运算符依赖于至少有一些有效的存储区域,您的地址为:

You could argue that the unary & operator relies on there being at least some valid region of storage that you have the address of:


否则,如果类型表达式是 T ,结果具有类型指向 T ,是一个prvalue,指定对象

Otherwise, if the type of the expression is T, the result has type "pointer to T" and is a prvalue that is the address of the designated object

一个对象被定义为一个存储区域。在引用的对象被销毁后,该存储区域不再存在。

And an object is defined as being a region of storage. After the object that is referred to is destroyed, that region of storage no longer exists.

我更喜欢相信,只有当无效对象是实际访问。参考仍然相信它指的是一些对象,它可以很高兴地给出它的地址,即使它不存在。

I prefer to believe that it will only result in undefined behaviour if the invalid object is actually accessed. The reference still believes it's referring to some object and it can happily give the address of it even if it doesn't exist. However, this seems to be an ill-specified part of the standard.

作为未定义行为的一个例子,考虑 x + x 。现在我们碰到了另一个不正常的标准部分。未指定 + 的操作数的值类别。通常从§5/ 8推断如果没有指定,那么它期望值为:

As an example of undefined behaviour, consider x + x. Now we hit another ill-specified part of the standard. The value category of the operands of + are not specified. It is generally inferred from §5/8 that if it is not specified, then it expects a prvalue:


每当glvalue表达式显示为应用期望该操作数的prvalue的运算符的操作数,应用左值到值(4.1),数组到指针(4.2)或函数到指针(4.3)的标准转换以将表达式转换为a prvalue。

Whenever a glvalue expression appears as an operand of an operator that expects a prvalue for that operand, the lvalue-to-rvalue (4.1), array-to-pointer (4.2), or function-to-pointer (4.3) standard conversions are applied to convert the expression to a prvalue.

现在因为 x 是一个左值, -rvalue转换是必需的,我们得到未定义的行为。这是有道理的,因为添加需要访问 x 的值,所以它可以计算出结果。

Now because x is an lvalue, the lvalue-to-rvalue conversion is required and we get undefined behaviour. This makes sense because addition requires accessing the value of x so it can work out the result.

这篇关于悬挂引用和未定义的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆