C++ 编译器支持检测返回对临时对象的引用

C++ compiler support to detect returning a reference to a temporary object

提问人:OnionKing 提问时间:3/19/2023 最后编辑:OnionKing 更新时间:3/19/2023 访问量:87

问:

有一个截图代码,它返回对临时对象的引用:

#include <iostream>
#include <string>

const std::string& forward(const std::string& s)
{
    return s;
}

int main()
{
    const std::string& hello = forward("this is a random string with a reference to a temporary object");
    std::cout << hello << "\n";
}

我编译了截图如下:

g++ -std=c++20 -Wpedantic -Wall test.cpp -o test

clang++ -std=c++20 -Wpedantic -Wall test.cpp -o test

我预计会收到一条警告消息,但没有关于“forward()”函数的这种错误使用的警告。warning: returning reference to temporary

是否有任何 C++ 编译器支持在返回临时对象时检测此类情况?

C 参考手册 G CLang++ 临时对象

评论

1赞 Richard Critten 3/19/2023
forward可以接受 rvalues 和 lValues。编译器必须对调用进行完整跟踪,以处理每次调用中传递的内容。如果更改为 是否收到错误?forwardconst std::string& forward(const std::string && s)
0赞 teapot418 3/19/2023
GCC 将生成您正在寻找的警告-O -Wall
0赞 OnionKing 3/19/2023
我尝试了 和 ,结果是一样的 - 没有警告/错误。G++ 版本:11.3.0const std::string && s-O -Wall
1赞 teapot418 3/19/2023
11.3 是沉默的,显然是在 gcc 12.x 中引入的
1赞 john 3/19/2023
forward仅当使用临时参数调用它时,才是一个潜在问题。就其本身而言,没有理由发出任何警告。

答:

4赞 user17732522 3/19/2023 #1

函数本身或对它的调用没有问题。返回时,临时对象仍处于活动状态。它的生存期仅在初始化 结束。因此,警告说该函数返回一个悬空引用是不正确的。函数调用的结果仍然可以在同一个完整表达式中使用,而不会出现任何悬空。forwardhello

只有在初始化后,您才会遇到问题,当立即变得悬空时。然后使用有UB。hellohellostd::cout << hello << "\n";

要识别 的初始化会导致在输出语句后面访问悬空指针,编译器至少需要内联 .因此,如果编译器的分析只能在启用优化的情况下检测到此问题,也就不足为奇了。helloforward

GCC 12 及更高版本似乎正是这种情况,它会在启用优化(至少 )和 .Clang 和 MSVC 目前似乎没有执行这样的分析。-O1-Wall

但是,我希望像 clang-analyze 这样的静态分析器以及像 ASAN(用于 GCC/Clang)这样的运行时清理器能够检测到这个问题(在我的测试中,ASAN 在任何优化级别上都对 GCC 和 Clang 都如此)。-fsanitize=address

评论

0赞 OnionKing 3/19/2023
ASAN 适用于 GCC (11.3.0) 和 Clang (14.0.0),但看起来只有 GCC12 可以在没有任何分析器/清理器的情况下检测到此问题(如@teapot418所述)。