首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >这是一个真正的问题吗:警告C4172:返回局部变量或临时地址

这是一个真正的问题吗:警告C4172:返回局部变量或临时地址
EN

Stack Overflow用户
提问于 2021-12-27 08:30:32
回答 3查看 342关注 0票数 2

下面的代码删除警告C4172:返回本地变量或临时地址。但我想知道在这种情况下这是一个真正的错误吗?我知道这里有很多类似的话题,我也从这个警告中读到了很多类似的话题。因此,在这种情况下,返回的值是来自"main“函数的指针,它应该是活动的,直到程序结束。如果returningLocalPointer将返回:"A某事;返回&某样东西;“那么是的,这将是一个问题,但在这种情况下,我们返回一个指针,该指针一直存在到"main”结尾。还是我错了?

代码语言:javascript
运行
复制
class A
{
};

A* returningLocalPointer(A* a)
{
    return a;
}

template<typename T>
T const& doWarning(T const& b)
{
    A* c = returningLocalPointer(b);
    return c;            // error if uses call-by-value
}

int main()
{
    A d;
    auto m = doWarning(&d);       //run-time ERROR
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-12-27 09:58:01

是的,这是个真正的问题。您的程序的行为没有定义。c是一个与b引用的指针不同的对象,它的生存期在doWarning的末尾结束。这两个指针指向同一个A对象(d),但这并不意味着它们是同一个对象。

为了举例说明,我将或多或少地逐行使用图表:

代码语言:javascript
运行
复制
A d;
auto m = doWarning(&d);

这将创建一个名为Ad对象,并将指向该对象的匿名指针传递给doWarning。稍后我将讨论m,但目前正在运行的对象如下所示:

代码语言:javascript
运行
复制
               d
┌─────┐       ┌─────┐
│     │       │     │
│  A* ├──────►│  A  │
│     │       │     │
└─────┘       └─────┘

代码语言:javascript
运行
复制
template<typename T>
T const& doWarning(T const& b)
{

在这里,T将被推断为A*,因为这就是传递给它的内容。doWarning通过引用接受它的参数,所以b的类型将是A* const &。也就是说,b是对来自maind的匿名指针的引用。

代码语言:javascript
运行
复制
 b                                 d
┌───────────┐       ┌─────┐       ┌─────┐
│           │       │     │       │     │
│ A* const& ├──────►│  A* ├──────►│  A  │
│           │       │     │       │     │
└───────────┘       └─────┘       └─────┘

代码语言:javascript
运行
复制
A* c = returningLocalPointer(b);

在这里,您创建了另一个指针c,它指向与b相同的对象。我不会看returningLocalPointer,因为它或多或少是不相关的。这一行可以用A* c = b;代替,不会有任何改变。您的对象现在看起来如下:

代码语言:javascript
运行
复制
 b                                 d
┌───────────┐       ┌─────┐       ┌─────┐
│           │       │     │       │     │
│ A* const& ├──────►│  A* ├──────►│  A  │
│           │       │     │       │     │
└───────────┘       └─────┘       └─────┘
                                     ▲
                     c               │
                    ┌─────┐          │
                    │     │          │
                    │  A* ├──────────┘
                    │     │
                    └─────┘

如您所见,c是一个与b引用的对象不同的对象。

代码语言:javascript
运行
复制
return c;

因为doWarning返回一个A* const& (因为TA*),所以初始化返回值以引用局部变量c

代码语言:javascript
运行
复制
 b                                 d
┌───────────┐       ┌─────┐       ┌─────┐
│           │       │     │       │     │
│ A* const& ├──────►│  A* ├──────►│  A  │
│           │       │     │       │     │
└───────────┘       └─────┘       └─────┘
                                     ▲
return value         c               │
┌───────────┐       ┌─────┐          │
│           │       │     │          │
│ A* const& ├──────►│  A* ├──────────┘
│           │       │     │
└───────────┘       └─────┘

代码语言:javascript
运行
复制
}

现在doWarning结束了,因此它的局部变量c超出了作用域,它的生存期结束了。这使得doWarning的返回值悬空:

代码语言:javascript
运行
复制
 b                                 d
┌───────────┐       ┌─────┐       ┌─────┐
│           │       │     │       │     │
│ A* const& ├──────►│  A* ├──────►│  A  │
│           │       │     │       │     │
└───────────┘       └─────┘       └─────┘

return value
┌───────────┐
│           │
│ A* const& ├──────► Nothing here anymore
│           │
└───────────┘

代码语言:javascript
运行
复制
auto m = doWarning(&d);

现在我们回到mauto本身永远不会推导出引用类型,因此m的类型被推断为A*。这意味着程序将尝试复制doWarning返回的引用所引用的指针。但是,doWarning的返回值引用的指针已经不存在了。尝试复制一个不存在的对象是一个错误,如果程序这样做,它的行为是未定义的。

票数 3
EN

Stack Overflow用户

发布于 2021-12-27 09:33:58

让我们用T = A*“实例化”这个函数(就像用doWarning(&d)调用它时一样):

代码语言:javascript
运行
复制
template
A* const& doWarning<A*>(A* const& b)
{
    A* c = returningLocalPointer(&b);
    return c;
}

你也许能看到问题出在哪里。c是通过引用返回的,但是它是一个局部变量,立即销毁,因此doWarning总是返回一个悬空引用。

MSVC似乎对指向本地的指针和对本地的引用使用相同的警告,这就是为什么它在谈论地址时实际上是关于引用的。GCC的警告可能会更加明确:

代码语言:javascript
运行
复制
In instantiation of 'const T& doWarning(const T&) [with T = A*]':
warning: reference to local variable 'c' returned [-Wreturn-local-addr]
    return c;            // error if uses call-by-value
           ^
note: declared here
    A* c = returningLocalPointer(b);
       ^
票数 2
EN

Stack Overflow用户

发布于 2021-12-27 08:53:32

您将返回对局部变量c的引用,因此您的代码具有未定义的行为。您可能会得到“幸运”,m将碰巧成为指向d的指针,但这并不能保证。

当它返回对d的引用而不是对c的引用时,该代码将定义行为,尽管它仍然有未定义的行为(因此可能仍然会产生警告),如果使用临时值调用doWarning

代码语言:javascript
运行
复制
A* returningLocalPointer(A* a)
{
    return a;
}

template<typename T>
T const& doWarning(T const& b)
{
    A* c = returningLocalPointer(&b);
    return *c;
}

int main()
{
    A d;
    auto& m = doWarning(d);
    // Undefined behaviour
    auto& n = doWarning(A{});
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70493226

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档