首页 > 解决方案 > 是否有将引用返回到临时的 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

标签: c++compiler-warningsmemory-safety

解决方案


详细版本有效,而表面相同的版本立即删除临时版本,留下悬空引用

你的代码根本不一样。在第一种情况下:

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
};

推荐阅读