15

给定以下函数,是否会在堆栈上声明每个局部变量?

std::string reallyCoolFunction(unsigned int a)
{
   if( a < 20 ) 
   {
     std::string result1 = "This function is really cool";
     return result1;
   }

   if( a >=20 && a <= 40 )
   {
     std::string result2 = "This function is kind of cool";
     return result2;
   }

   if( a > 40 )
   {
     std::string result3 = "This function is moderately cool";
     return result3;
   }

 std::string result4 = "This function really isn't that cool"; 
 return result4; // remove warning

}

在这种情况下,std::string实际上只需要一个,是全部 4 个都分配到堆栈上,还是只分配 1 个?

4

6 回答 6

14

决定权取决于编译器:由于自动变量在下一个变量进入作用域之前就超出了作用域,编译器可以重新使用它们的内存。请记住,“堆栈”变量实际上是根据 C++ 规范具有自动存储持续时间的变量,因此它们可能根本不在堆栈上。

于 2013-01-22T15:17:34.587 回答
10

在大多数编译器上,只会分配一个字符串。请记住,尽管std::string使用动态内存,因此其大部分内容仍将分配在堆上。

于 2013-01-22T15:16:56.053 回答
6

很可能是01(在 Release 中),当然也可能是4(在 Debug 中)。

这称为 RVO:返回值优化。

实际上允许编译器完全省略副本并std::string直接在调用者提供的插槽中构建。这是特定于 ABI 的,并且所有优化仅适用于满足多个标准的情况;在您的情况下,它很可能会适用。

如果您想检查,您可以尝试仔细阅读编译器在其翻译/优化管道的各个阶段的输出;尽管取决于您的工具链,但这可能会很困难。

于 2013-01-22T15:47:53.380 回答
2

取决于编译器。
如果编译器足够智能,可以最终确定只需要一个字符串,它将只为一个字符串发出代码。

你的编译器足够智能吗?

最简单的方法是检查生成的汇编代码。

是全部 4 个都分配到堆栈上,还是只分配 1 个?

无论是 1 个字符串还是 4 个字符串,字符串对象都位于函数本地的堆栈上,但字符串的内存是在 freestore 中分配的。

于 2013-01-22T15:17:22.327 回答
0

在这种情况下,允许编译器创建 4、1、2 或 3 个变量。但是我知道的大多数编译器只会创建一个,或者可能是两个,因为 result4 在函数的整个范围内。

当然,如果你做了“正确”的事情,编译器很可能会感到困惑并且做的比它绝对需要的更多,所以在关键功能中依赖它并不是一件特别好的事情。

编辑:我应该补充一点,std::string 的构造函数只有在对象实际上被“使用”时才应该运行,所以你可能会使用堆栈空间,但它不应该调用构造函数。如果您执行以下操作,这一点很重要:

void func()
{
    if (something)
    {
        Lock myLock(&global_lock_object);   // Constructor locks global_lock_object
        ... do stuff that needs global_lock_object locked ... 
        // end of scope runs destructor of Lock that unlocks global_lock_object. 
    }
    ... more code that takes a long time to execute but doesn't need lock. ...
}

现在,如果 for 的构造函数Lock“过早”执行,并且在相同的范围内被破坏[并且它应该是对称的],那么锁将在函数的整个持续时间内被持有,这是错误的。

于 2013-01-22T15:22:25.077 回答
0

简短的回答:看看汇编程序。

长答案:编译器可能会应用静态检查来确定他是否需要全部 4 个或只需要一些变量。有些编译器可能会在调试模式下分配 4 个不同的变量,有些可能不会。在发布模式下,一些优化器可能会看到前 3 个都在自己的范围内,因此可以放在同一个地方。因此,这些编译器可以为堆栈上的两个字符串变量保留空间。需要更多分析才能看到第四个变量在任何情况下都不会与前三个变量共存,因此一些优化器可能会将剩余的两个变量也放在同一个位置。

但是你的编译器是否这样做,以及他是否仍然在稍微复杂一点的情况下这样做,只有在你分析输出时才能确定。

于 2013-01-22T15:24:31.047 回答