我重新开始使用 c++ 并正在考虑变量的范围。如果我在函数中有一个变量,然后我返回该变量,该变量在返回时是否不会“死”,因为它所在的范围已经结束?
我已经用一个返回字符串的函数尝试了这个,它确实有效。谁能解释一下?或者至少请给我指出一个可以向我解释的地方。
谢谢
我重新开始使用 c++ 并正在考虑变量的范围。如果我在函数中有一个变量,然后我返回该变量,该变量在返回时是否不会“死”,因为它所在的范围已经结束?
我已经用一个返回字符串的函数尝试了这个,它确实有效。谁能解释一下?或者至少请给我指出一个可以向我解释的地方。
谢谢
当函数终止时,会发生以下步骤:
函数的返回值被复制到为此目的而放入堆栈的占位符中。
弹出堆栈帧指针之后的所有内容。这会破坏所有局部变量和参数。
返回值从堆栈中弹出并分配为函数的值。如果函数的值没有分配给任何东西,则不会发生分配,并且值会丢失。
下一条要执行的指令的地址从堆栈中弹出,CPU 从该指令处恢复执行。
当您返回一个值时,会生成一个副本。局部变量的作用域结束,但会创建一个副本,并返回给调用函数。例子:
int funcB() {
int j = 12;
return j;
}
void A() {
int i;
i = funcB();
}
j (12) 的值被复制并返回给 i,这样 i 将收到 12 的值。
这实际上取决于您要返回的变量类型。如果您返回一个原语,那么它是通过复制而不是通过引用返回的,因此该值被复制到调用函数可以获得它的堆栈顶部(或者,更常见的是放置到寄存器中)。如果您在堆上分配一个对象或内存并返回一个指针,那么它不会死,因为它在堆上,而不是堆栈上。但是,如果您在堆栈上分配一些东西并返回它,那将是一件坏事。例如,其中任何一个都非常糟糕:
int *myBadAddingFunction(int a, int b)
{
int result;
result = a + b;
return &result; // this is very bad and the result is undefined
}
char *myOtherBadFunction()
{
char myString[256];
strcpy(myString, "This is my string!");
return myString; // also allocated on the stack, also bad
}
只是为了多一点面向内存模型的解释:当调用函数时,会为函数创建一个临时空间来放置其局部变量,称为frame。当函数(被调用者)返回它的值时,它将返回值放入调用它的函数(调用者)的框架中,然后被调用者框架被销毁。
“框架被破坏”部分是为什么你不能从函数返回指针或对局部变量的引用。指针实际上是一个内存位置,因此一旦帧被销毁,返回局部变量(根据定义:帧内的变量)的内存位置就变得不正确。由于被调用者框架在返回其值后立即被销毁,因此对局部变量的任何指针或引用都会立即不正确。
局部变量被复制到返回值。复制构造函数被调用用于非平凡的类。
如果您返回一个指向局部变量的指针或引用,您将遇到麻烦——正如您的直觉所建议的那样。
这取决于退货商品的类型。如果您按值返回,则会创建一个新的变量副本以返回给调用者。我认为您不需要担心对象的生命周期,但您可能需要担心复制对象的成本(但请不要过早优化 - 正确性更为重要):
std::string someFunc( std::string& const s)
{
return s + "copy";
}
如果函数返回一个引用,那么你需要小心你返回的内容,因为它的生命周期需要超出函数的生命周期,delete
如果你new
用来创建对象,调用者不一定能够做到:
std::string& someFunc2( std::string const& s)
{
return s + "reference to a copy"; // this is bad - the temp object created will
// be destroyed after the expression the
// function call is in finishes.
// Some, but not all, compilers will warn
// about this.
}
当然,返回指针也会有类似的生命周期考虑。