给定以下函数,是否会在堆栈中声明每个局部变量?
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个?
答案 0 :(得分:14)
决定取决于编译器:由于自动变量超出范围,然后下一个变量进入范围,编译器可以重新使用它们的内存。请记住,根据C ++规范,“堆栈”变量实际上是具有自动存储持续时间的变量,因此它们可能根本不在堆栈中。
答案 1 :(得分:10)
在大多数编译器中,只会分配一个字符串。请记住,std::string
使用动态内存,因此大部分内容仍将在堆上分配。
答案 2 :(得分:6)
很可能 0 或者 1 (在发布中),当然 4 (在调试中)。
这称为RVO:返回值优化。
实际上允许编译器完全删除副本并直接在调用者提供的 slot 中构建std::string
。这是ABI特定的,因为所有优化仅适用于满足多个标准的情况;在你的情况下,它很可能适用。
如果要检查,可以尝试在其转换/优化管道的各个阶段仔细阅读编译器的输出;它可能很难,但取决于你的工具链。
答案 3 :(得分:2)
取决于编译器。
如果编译器足够智能,最终确定只需要一个字符串,那么它只会为一个字符串发出代码。
您的编译器是否足够智能?
最简单的方法是检查生成的汇编代码。
是否所有4个都在堆栈上分配,或者只分配了1个?
无论是1个还是4个字符串,字符串对象都位于函数本地的堆栈中,但字符串的内存是在freestore中分配的。
答案 4 :(得分: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. ...
}
现在,如果Lock
的构造函数“太早”执行,并且在同一范围内被破坏[并且它应该是对称的],那么锁定将在函数的整个持续时间内保持,这将是是错的。
答案 5 :(得分:0)
简短回答:看看汇编程序。
答案很长:编译器可以应用静态检查来确定他是否需要全部4个或只需要一些变量。有些编译器可能会在调试模式下分配4个不同的变量,有些可能不会。在发布模式下,一些优化器可能会看到前三个都在各自的范围内,因此可以放在同一个地方。因此,这些编译器可以为堆栈上的两个字符串变量保留空间。它需要更多的分析才能看到第四个变量在任何情况下都不会与前三个变量共存,因此一些优化器可能会将这两个变量放在同一个地方。
但是 你的编译器是否会这样做,以及他是否仍然在稍微复杂的情况下这样做,只能确定你是否分析了输出。