这是最近出现的事情,我认为它显然不应该起作用:
#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 Studio,Clang和GCC的最终输出是相同的:
我正在使用非const引用临时文件! 5正在删除!
通过某种机制扩展了所得shared_ptr
的寿命,以匹配std::shared_ptr<int>& ptr
的寿命。
现在,我知道在使用常量引用的情况下,临时对象的生存期将延长到引用的生存期。但是唯一的命名对象是非常量引用,我希望所有其他中间表示形式的生存期仅等于初始化表达式。
此外,Microsoft拥有一个扩展,该扩展允许非const引用延长绑定临时临时文件的寿命,但是即使禁用了该扩展,该行为似乎仍然存在,此外,它还在Clang和GCC中出现。
根据this answer,我认为该临时对象是隐式创建为const
的,因此尝试修改ptr
所引用的对象可能是未定义的行为,但是我不确定知识告诉我任何有关延长寿命的原因。我的理解是,修改是UB的const的行为,而不仅仅是对它的非const引用。
我对应该发生的事情的理解如下:
Type()
创建一个没有简历规范的prvalue。
static_cast<const Type&>(...)
将该prvalue实例化为const xvalue,其生存期等于内部表达式。然后,我们创建对该const xvalue的const lvalue引用。 xvalue的生存期得以延长,以匹配const lvalue引用的生存期。
const_cast<Type&>(...)
产生一个左值引用,然后将其分配给ptr
。 const左值引用随即失效,并带有物化的左值。
我尝试阅读悬而未决的参考书ptr
,并且发生了不好的事情。
我的理解有什么问题?为什么不出现斜体字呢?
作为一个额外的奖励问题,我是否正确地认为底层对象是const,并且通过此路径修改它的任何尝试都会导致不确定的行为?
答案 0 :(得分:2)
任何引用都可以延长对象的寿命。但是,非const引用不能像您的示例那样绑定到临时目录。您引用的Microsoft扩展不是“通过非const引用延长生存期”,而是“让非const引用绑定到临时对象”。他们具有该扩展功能,以便与他们自己以前的损坏的编译器版本向后兼容。
通过强制转换,您已将非常量引用强制绑定到临时文件,这似乎无效,只是不寻常,因为它不能直接完成。完成绑定后,非const引用的生存期将与const引用相同。
更多信息:Do *non*-const references prolong the lives of temporaries?
答案 1 :(得分:0)
链接的文章显然是错误的。临时不是(不一定)const对象。它不能绑定到非常量引用这一事实并不重要。它可以绑定到右值引用而无需强制转换,并可以通过此类引用进行修改。这样做没有UB。一个人也可以临时调用非const成员函数。移动语义的整个概念都基于这一事实。
绑定到普通的非常量引用并进行修改是完成同一件事的另一种方式。它需要强制转换,但是与上面的非常相似。