【发布时间】:2010-09-21 11:19:59
【问题描述】:
我重新开始使用 c++ 并且正在考虑变量的范围。 如果我在函数中有一个变量,然后我返回该变量,该变量在返回时是否不会“死”,因为它所在的范围已经结束?
我已经尝试过使用返回字符串的函数,它确实有效。 谁能解释一下?或者至少请给我指出一个可以向我解释这一点的地方。
谢谢
【问题讨论】:
标签: c++ return-value scope
我重新开始使用 c++ 并且正在考虑变量的范围。 如果我在函数中有一个变量,然后我返回该变量,该变量在返回时是否不会“死”,因为它所在的范围已经结束?
我已经尝试过使用返回字符串的函数,它确实有效。 谁能解释一下?或者至少请给我指出一个可以向我解释这一点的地方。
谢谢
【问题讨论】:
标签: c++ return-value scope
这取决于退货商品的类型。如果您按值返回,则会创建一个新的变量副本以返回给调用者。我认为您不需要担心对象的生命周期,但您可能需要担心复制对象的成本(但请不要过早优化 - 正确性更为重要):
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.
}
当然,返回指针也会有类似的生命周期考虑。
【讨论】:
只是为了多一点面向内存模型的解释:当调用函数时,会为函数腾出一个临时空间来放置其局部变量,称为 frame。当函数(被调用者)返回其值时,将返回值放入调用它的函数(调用者)的框架中,然后被调用者框架被销毁。
“框架被破坏”部分是为什么您不能从函数返回指针或对局部变量的引用。指针实际上是一个内存位置,因此一旦帧被销毁,返回局部变量(根据定义:帧内的变量)的内存位置就变得不正确。由于被调用者框架在返回值后立即被销毁,因此任何指向局部变量的指针或引用都会立即不正确。
【讨论】:
当函数终止时, 发生以下步骤:
函数的返回值为 复制到原来的占位符中 为此目的放入堆栈。
堆栈帧之后的所有内容 指针弹出。这破坏 所有局部变量和参数。
返回值被弹出 堆栈并分配为值 的功能。如果值 函数没有分配给任何东西, 没有分配发生,并且 价值丢失。
下一条指令的地址 执行从堆栈中弹出, CPU 恢复执行 那条指令。
【讨论】:
这实际上取决于您返回的变量类型。如果您返回一个原语,那么它是通过复制而不是通过引用返回的,因此该值被复制到调用函数可以获取它的堆栈顶部(或者,更常见的是放入寄存器中)。如果您在堆上分配一个对象或内存并返回一个指针,那么它不会死,因为它在堆上,而不是在堆栈上。但是,如果您在堆栈上分配一些东西并返回它,那将是一件坏事。例如,其中任何一个都非常糟糕:
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
}
【讨论】:
当您返回一个值时,会生成一个副本。局部变量的作用域结束,但会创建一个副本,并返回给调用函数。示例:
int funcB() {
int j = 12;
return j;
}
void A() {
int i;
i = funcB();
}
将 j (12) 的值复制并返回给 i,以便 i 收到 12 的值。
【讨论】:
i 在这种情况下是一个结构对象,那么我将&i 作为一个参数传递给funcB - funcB 不会返回任何东西,只是使用i结构成员计算,我需要malloci吗?没有权利?因为i的值还在void A()的范围内,所以我不怕在funcB结束后生命周期结束
局部变量被复制到返回值。复制构造函数被调用用于非平凡的类。
如果您返回一个指针或对局部变量的引用,您将遇到麻烦——正如您的直觉所建议的那样。
【讨论】: