c++ - 是否有将引用返回到临时的 C++ 警告?
问题描述
这种情况有一个错误:
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
情况下,我知道这个警告会非常棘手,因为对于编译器来说,const int&
返回的std::vector<int>::operator[](size_t) const
不是对临时的引用。不过,我实际上对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 ca(); a.get() 在 0x7ffeeef2cb58 返回 A::~A 0x7ffeeef2cb58 C::~C 0x7ffeeef2cb68 1234 C::C 0x7ffeeef2cb68 A::A 0x7ffeeef2cb58 A::~A 0x7ffeeef2cb58 ca().get() 在 0x7ffeeef2cb58 返回 C::~C 0x7ffeeef2cb68 -1
解决方案
详细版本有效,而表面相同的版本立即删除临时版本,留下悬空引用
你的代码根本不一样。在第一种情况下:
const auto& a = c.a();
const auto& x = a.get();
临时扩展的生命周期为 const 引用的生命周期,所以x
只要a
有效就有效,但在第二个:
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
};
推荐阅读
- node.js - 错误:ENOENT:没有这样的文件或目录,打开“dist/index.html”
- java - 使用 Apache Arrow 读取 Parquet 文件
- bash - 如何使用 sed 删除从 pattern_1 到第二次出现 pattern_2 的行?
- php - 无法使用 xampp 在本地主机上使用自定义域
- ionic-framework - Ionic 4 App 上传到应用商店并出现警告
- html - 从多个表单中读取通过单个按钮提交的烧瓶中的多个文件
- visual-studio-2019 - 如何从 Visual Studio 运行 Tizen 证书管理器
- sas - 如何在 SAS 中输入带有数字名称的变量?
- flask - 使用烧瓶在网页上显示存储在 s3 中的图像
- mysql - NULL 值不会插入到 sql 表中