通过使用 const-cast 的非常量引用来延长临时的寿命
Lifetime extension of temporary by non-const reference using const-cast
这是最近出现的东西,我觉得它不应该像它显然那样工作:
#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的结果输出是相同的:
我正在使用一个非常量参考来临时! 5 删除!
这意味着通过某种机制,生成的shared_ptr
的寿命已延长以匹配std::shared_ptr<int>& ptr
的寿命。
发生了什么事情?
现在,我知道临时的生存期将延长到常量引用情况下的引用的生存期。但是唯一的命名对象是一个非常量引用,我希望所有其他中间表示的生存期仅等于初始化表达式。
此外,Microsoft有一个扩展,它允许非常量引用延长绑定临时的生存期,但即使禁用该扩展,这种行为似乎也存在,此外,也出现在 Clang 和 GCC 中。
根据这个答案,我相信临时是隐式创建的const
,所以试图修改ptr
引用的对象可能是未定义的行为,但我不确定知识告诉我为什么寿命被延长。我的理解是,这是修改UB 的常量的行为,而不是简单地对它进行非常量引用。
我对应该发生的事情的理解如下:
Type()
创建一个没有 cv 规范的 prvalue。static_cast<const Type&>(...)
将该 prvalue 具体化为具有等于内部表达式的 const x值。然后,我们创建一个对该常量 xvalue 的常量左值引用。x值的生存期延长以匹配常量左值引用的生存期。const_cast<Type&>(...)
生成一个左值引用,然后将其分配给ptr
。然后,常量左值引用过期,并随之而来具体化的 xvalue。我试着阅读悬而未决的参考
ptr
,坏事发生了。
我的理解有什么问题?为什么斜体中的位不发生?
作为一个额外的奖励问题,我是否正确地认为底层对象是常量,并且任何通过此路径修改它的尝试都会导致未定义的行为?
任何引用都可以延长对象的生存期。 但是,非常量引用不能绑定到临时引用,如示例中所示。 您引用的Microsoft扩展不是"通过非常量引用延长生存期",而是"让非常量引用绑定到临时引用"。 他们具有该扩展,以便与自己以前损坏的编译器版本向后兼容。
通过强制转换,您强制将非常量引用绑定到临时引用,这似乎不是无效的,只是不寻常,因为它不能直接完成。 完成该绑定后,非常量引用的生存期延长与常量引用的生存期延长相同。
更多信息:*非*常量引用会延长临时人员的寿命吗?
链接的文章显然是错误的。临时对象(不一定(是常量对象。它不能绑定到非常量引用这一事实并不重要。它可以绑定到右值引用,而无需强制转换,并通过此类引用进行修改。这样做没有UB。也可以临时调用非常量成员函数。移动语义的整个概念就是基于这一事实。
绑定到正常的非常量引用并通过它进行修改是伴随同一事物的不同方法。它需要演员表,但除此之外,它与上述非常相似。
- 如何理解C++标准N3337中的expr.const.cast子句8
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 如何在 c++ 中将向量转换为<string>常量字符* const*?
- 通过使用 const-cast 的非常量引用来延长临时的寿命
- 将字符串文本常量定义为 char const* 和 wchar const*
- 什么是常量指针常量引用类型的参数?(const X* const & p)
- 编译器在传递 const 变量时返回错误:模板参数不是常量表达式
- 非常量调用 const 成员函数失败,只读位置C++
- 为什么我不能使用与"常量字符*"相同的"const int*"创建一个 int 数组?
- 与其他静态const成员初始化静态常量成员
- 为什么静态常量字符 * const 变量在为左值时可绑定到右值引用参数
- std::转换为常量字符 * 的字符串在 std::unordered_set<const 字符 * 中找不到>
- 返回非常量引用编译的 Const 方法
- 为什么使用带有 const 的方法而不是第一个没有常量的方法
- 如何使用常量变量初始化类的 const 成员变量
- 从 sub_match<常量字符 *>' 转换为'const char *const &'
- 是否允许在常量定义的对象上丢弃 const 只要它没有实际被修改?
- 为什么"const T&"不确定是常量?
- "const int <variable>" 不能出现在常量表达式中
- C++ const-cast 一个引用