gpt4 book ai didi

c++ - 防弹 C++ 临时生命周期?

转载 作者:搜寻专家 更新时间:2023-10-31 00:50:13 26 4
gpt4 key购买 nike

重新审视 C++ 中的生命周期扩展,我发现有一些模式破坏了 C++ 表达式的“可分解性”。例如,以下两个 block 是一个 valid C++ code :

class NonMovable {
public:
NonMovable(NonMovable&&) = delete;
NonMovable(const NonMovable&) = delete;
NonMovable();

int Value() const;
};

template <class T>
const T& identity(const T& x) {
return x;
}

template <class T>
class A {
public:
explicit A(const T& value) : value_(value) {}
const T& GetValue() const {
return value_;
}
private:
const T& value_;
};

正确用法:

int main() {
int retcode = identity(
identity(/*tmp1*/ A(/*tmp2*/ NonMovable{}).GetValue())).Value();
// tmp1 and tmp2 end their lifetimes here:
// their full-expression is the whole previous line
return retcode;
}

但是如果我们分解 main 中的第一个表达式,它就变得无效了:

int main() {
auto&& a_obj = /*tmp1*/ A(/*tmp2*/ NonMovable{});
// tmp2 lifetime ends here

// oops! dereferencing dangling reference:
int retcode = identity(
identity(a_obj.GetValue())).Value();
return retcode;
// tmp1 lifetime ends here
}

我的问题是:是否可以禁用第二种用法?

P.S.:我不太确定第二个 main 是否引入了 UB,因为我有 tested它带有 clang -Wlifetime,它不会提示。但我仍然相信它是UB。在现实生活中,我遇到过类似的行为:如果我将单个表达式分解为两个单独的表达式,代码就会崩溃,发出 UBSan 警告和段错误。

P.P.S.:那些 identity 并不重要,如果我正确理解对象的生命周期(我现在对此表示怀疑)

最佳答案

您的分析是正确的。如果没有生命周期延长,所有临时对象都会在“完整表达式”的末尾被销毁,即 ; 在该行的末尾。所以当你说

int retcode = A(NonMovable{}).GetValue().Value();

(为清楚起见删除了注释和 identity 调用)然后一切正常; NonMovable 对象在您请求它的值时仍然存在。

另一方面,当你说

auto&& a_obj = A(NonMovable{});

然后 NonMovable 在行尾被销毁,A 对象将持有悬空引用。 (顺便说一句,auto&& 只是在此处延长了临时 A 的生命周期——您也可以只使用普通的 auto)

My question is: Is it possible to disable the second kind of usage?

不是真的,至少据我所知。您可以添加一个已删除的 A(NonMovable&&) 构造函数,但这也会阻止第一个示例中的“正确”用法。这与 std::string_view 发生的问题完全相同(C++20 中的 std::span 也会发生)——本质上,您的 类具有引用语义,但指的是一个已被销毁的临时对象。

关于c++ - 防弹 C++ 临时生命周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58166210/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com