这是最近出现的事情,我觉得它不应该像表面上那样起作用:
#include <iostream>
#include <memory>
int main()
{
std::shared_ptr<int>& ptr = const_cast<std::shared_ptr<int>&>(
static_cast<const std::shared_ptr<int>&>(
std::shared_ptr<int>(
new int(5), [](int* p) {std::cout << "Deleting!"; *p = 999; delete(p); }
)
)
);
std::cout << "I'm using a non-const ref to a temp! " << *ptr << " ";
}这里没有必要使用shared_ptr,但是自定义删除器允许简单地演示结果对象的生存期。Visual、Clang和GCC的输出结果是相同的:
我正在使用一个非const到一个临时的!5删除!
这意味着,通过某种机制,结果shared_ptr的生存期已经进行了扩展,以与std::shared_ptr<int>& ptr相匹配。
发生什么事了呢?
现在,我意识到一个临时的生命周期将被扩展到一个常数引用的情况下的引用。但是唯一被命名的对象是一个非const引用,所有其他的中间表示,我期望它的生命周期仅等于初始化表达式。
此外,微软还有一个扩展,允许非const引用延长绑定临时的生存期,但即使禁用了该扩展,这种行为也会出现在Clang和GCC中。
根据this answer的说法,我认为临时是隐式地作为const创建的,因此试图修改ptr引用的对象可能是未定义的行为,但我不确定知识是否告诉我为什么要延长生命周期。我的理解是,修改const的行为就是UB,而不是简单地引用它。
我对将要发生的事情的理解如下:
Type()创建没有cv-specification.static_cast<const Type&>(...)的prvalue,将该prvalue具体化为const,其生存期等于内部表达式。然后,我们创建一个对该const的const引用。扩展xvalue的生存期以与const reference.const_cast<Type&>(...)的生存期匹配,生成一个lvalue引用,然后将其分配给ptr。const引用随后到期,并带着物化的xvalue。ptr和坏事情发生。我的理解有什么不对?为什么斜体的部分不发生呢?
作为一个额外的额外问题,我是否正确地认为潜在的对象是const,通过这条路径修改它的任何尝试都会导致未定义的行为?
发布于 2019-12-04 12:53:24
任何引用都可以延长对象的生存期。但是,非const引用不能绑定到临时引用,如您的示例所示。您所指的Microsoft扩展不是“通过非const引用扩展生存期”,而是“让非const引用绑定到临时用户”。为了向后兼容他们自己以前的坏编译版本,他们有这个扩展。
通过强制转换,您强制将非const引用绑定到临时引用,这似乎并不是无效的,只是不正常,因为它不能直接执行。一旦完成了绑定,非const引用的生存期扩展就会发生,就像对const引用一样。
更多信息:Do *non*-const references prolong the lives of temporaries?
发布于 2019-12-04 14:03:29
链接的文章显然是错误的。临时对象不一定是const对象。它不能与非约束约束相结合这一事实并不重要。它可以绑定到不需要强制转换的rvalue引用,并且可以通过这样的引用进行修改。这样做是不可能的。还可以在临时函数上调用非const成员函数。移动语义的整个概念就是基于这一事实。
绑定到一个正常的非连接引用并通过它进行修改是实现同一件事情的另一种方式。它需要一个转换,但否则它是非常类似于上述。
https://stackoverflow.com/questions/59175900
复制相似问题