[英]Is there a C++ warning for returning a reference into a temporary?
这种情况有一个错误:
const int& foo() {
const int x = 0;
return x;
}
乃至
const int& foo() {
const std::pair<int,int> x = {0,0};
return x.first;
}
但不是这个:
const int& foo() {
const std::array<int,1> x = {0};
return x[0];
}
(不太令人惊讶)不是这样的:
const int& foo() {
const std::vector<int> x = {0};
return x[0];
}
特别是在std::vector
情况下,我得到这个警告会非常棘手,因为编译器并不明显std::vector<int>::operator[](size_t) const
返回的const int&
是一个引用到临时。 我实际上有点惊讶std::array
没有失败,因为这个类似的情况确实给了我一个错误:
struct X {
int x[0];
};
const int& foo() {
X x;
return x.x[0];
}
任何流行的编译器都有警告/错误可以捕获这些情况吗? 我可以想象一个保守的版本会警告返回来自临时成员函数调用的引用。
我用以下内容绊倒了这个,其中我内联了一系列链接调用,但是因为C ++允许你将locals分配给const&
,所以详细版本可以工作,而表面上相同的版本会立即删除临时版本,留下悬空参考:
#include <iostream>
struct A {
int x = 1234;
A() { std::cout << "A::A " << this << std::endl; }
~A() { x = -1; std::cout << "A::~A " << this << std::endl; }
const int& get() const { return x; }
};
struct C {
C() { std::cout << "C::C " << this << std::endl; }
~C() { std::cout << "C::~C " << this << std::endl; }
A a() { return A(); }
};
int foo() {
C c;
const auto& a = c.a();
const auto& x = a.get();
std::cout << "c.a(); a.get() returning at " << &x << std::endl;
return x;
}
int bar() {
C c;
const int& x = c.a().get();
std::cout << "c.a().get() returning at " << &x << std::endl;
return x;
}
int main() {
std::cout << foo() << std::endl;
std::cout << bar() << std::endl;
}
那输出
C::C 0x7ffeeef2cb68 A::A 0x7ffeeef2cb58 c.a(); a.get() returning at 0x7ffeeef2cb58 A::~A 0x7ffeeef2cb58 C::~C 0x7ffeeef2cb68 1234 C::C 0x7ffeeef2cb68 A::A 0x7ffeeef2cb58 A::~A 0x7ffeeef2cb58 c.a().get() returning at 0x7ffeeef2cb58 C::~C 0x7ffeeef2cb68 -1
详细版本可以正常工作,而表面相同的版本会立即删除临时版本,留下悬空参考
您的代码完全不相同。 在第一种情况:
const auto& a = c.a();
const auto& x = a.get();
临时扩展的生命周期为const引用的生命周期,因此只要a
有效, x
就有效,但在第二个:
const int& x = c.a().get();
你有悬挂参考x
。 你在这里的情况与你之前显示的例子无关 - 当你返回一个对本地变量的悬空引用时,因此警告你正在查看几乎不相关的例子,如果编译器会检测到你在实际代码中描述的情况。
虽然可以由A
类设计师为您的案例解决方案:
struct A {
int x = 1234;
A() { std::cout << "A::A " << this << std::endl; }
~A() { x = -1; std::cout << "A::~A " << this << std::endl; }
const int& get() const & { return x; }
int get() && { return x; } // prevent dangling reference or delete it to prevent compilation
};
使用寿命已结束的值是未定义的行为,请参阅[basic.life] /6.1 。 该标准不要求编译器输出任何 UB诊断。
因此,您所看到的诊断只是对编译器的礼貌。 很高兴看到你得到了其中的一些,但是你注意到它们肯定远非防水。
是的,终身延伸不可链接。 这使得它非常危险和不可靠。
您可以尝试Clang的Address Sanitizer(ASAN)。
事实上,ASAN似乎正在捕捉你的问题( -fsanitize-address-use-after-scope
):
==35463==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fffffffe970 at pc 0x000000498d53 bp 0x7fffffffe910 sp 0x7fffffffe908
READ of size 4 at 0x7fffffffe970 thread T0
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.