28

我重新开始使用 c++ 并正在考虑变量的范围。如果我在函数中有一个变量,然后我返回该变量,该变量在返回时是否不会“死”,因为它所在的范围已经结束?

我已经用一个返回字符串的函数尝试了这个,它确实有效。谁能解释一下?或者至少请给我指出一个可以向我解释的地方。

谢谢

4

6 回答 6

48

当函数终止时,会发生以下步骤:

  • 函数的返回值被复制到为此目的而放入堆栈的占位符中。

  • 弹出堆栈帧指针之后的所有内容。这会破坏所有局部变量和参数。

  • 返回值从堆栈中弹出并分配为函数的值。如果函数的值没有分配给任何东西,则不会发生分配,并且值会丢失。

  • 下一条要执行的指令的地址从堆栈中弹出,CPU 从该指令处恢复执行。

栈和堆

于 2008-11-08T21:26:28.817 回答
4

当您返回一个值时,会生成一个副本。局部变量的作用域结束,但会创建一个副本,并返回给调用函数。例子:

int funcB() {
  int j = 12;
  return j;
}

void A() {
  int i;
  i = funcB();
}

j (12) 的值被复制并返回给 i,这样 i 将收到 12 的值。

于 2008-11-08T21:23:50.570 回答
4

这实际上取决于您要返回的变量类型。如果您返回一个原语,那么它是通过复制而不是通过引用返回的,因此该值被复制到调用函数可以获得它的堆栈顶部(或者,更常见的是放置到寄存器中)。如果您在堆上分配一个对象或内存并返回一个指针,那么它不会死,因为它在堆上,而不是堆栈上。但是,如果您在堆栈上分配一些东西并返回它,那将是一件坏事。例如,其中任何一个都非常糟糕:

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
}
于 2008-11-08T21:25:29.597 回答
3

只是为了多一点面向内存模型的解释:当调用函数时,会为函数创建一个临时空间来放置其局部变量,称为frame。当函数(被调用者)返回它的值时,它将返回值放入调用它的函数(调用者)的框架中,然后被调用者框架被销毁。

“框架被破坏”部分是为什么你不能从函数返回指针或对局部变量的引用。指针实际上是一个内存位置,因此一旦帧被销毁,返回局部变量(根据定义:帧内的变量)的内存位置就变得不正确。由于被调用者框架在返回其值后立即被销毁,因此对局部变量的任何指针或引用都会立即不正确。

于 2008-11-08T21:37:29.760 回答
2

局部变量被复制到返回值。复制构造函数被调用用于非平凡的类。

如果您返回一个指向局部变量的指针或引用,您将遇到麻烦——正如您的直觉所建议的那样。

于 2008-11-08T21:21:15.660 回答
2

这取决于退货商品的类型。如果您按值返回,则会创建一个新的变量副本以返回给调用者。我认为您不需要担心对象的生命周期,但您可能需要担心复制对象的成本(但请不要过早优化 - 正确性更为重要):

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

当然,返回指针也会有类似的生命周期考虑。

于 2008-11-09T00:32:39.890 回答