在这个例子中,为什么返回堆栈变量是可以的?当t()返回时,为什么它不返回垃圾,因为堆栈指针已递增?
#include << string >>
#include << vector >>
#include << iostream >>
using namespace std;
class X{
public:
X() { cout << "constructor" << endl; }
~X() { cout << "destructor" << endl; }
};
vector <X> t()
{
cout << "t() start" << endl;
vector<X> my_x;
int i = 0;
printf("t: %x %x %x\n", t, &my_x, &i);
my\_x.push\_back(X()); my\_x.push\_back(X()); my\_x.push\_back(X());
cout << "t() done" << endl;
return my_x;
}
int main()
{
cout << "main start" << endl;
vector <X> g = t();
printf("main: %x\n", &g);
return 0;
}
输出:
./a.out
main start
t() start
t: 8048984 bfeb66d0 bfeb667c
constructor
destructor
constructor
destructor
destructor
constructor
destructor
destructor
destructor
t() done
main: bfeb66d0
destructor
destructor
destructor
答案 0 :(得分:22)
基本上,当您返回堆栈变量my_x
时,将调用复制构造函数来创建变量的新副本。 这不是真的,在这种情况下,感谢所有强大的编译器。
编译器使用一种称为按值优化返回的技巧,使变量my_x真正构造在main
方法上为g分配的内存位置。这就是您看到正在打印的地址bfeb66d0
的原因。这样可以避免内存分配和复制构建。
有时由于代码的复杂性,这根本不可能,然后编译器重置为默认行为,创建对象的副本。
答案 1 :(得分:5)
因为参数是按值传递的。制作副本。所以返回的不是堆栈上的值,而是它的副本。
答案 2 :(得分:0)
返回一个副本,唯一不能返回它的副本的构造是静态数组。所以你不能这样说......
int[] retArray()
{
int arr[101];
return arr;
}
答案 3 :(得分:0)
编译器经过优化,可以处理返回的#34;堆栈变量&#34;不调用复制构造函数。您唯一需要知道的是内存分配是在堆栈上分配它的函数和返回对象的函数的范围。
它不会调用复制构造函数,也不会分配两次。
可能存在一些特殊情况,当然这取决于编译器 - 例如,可能会复制基元 - 但一般情况下,堆栈中分配的对象在返回时不会被复制。 / p>
示例:
struct Test {
};
Test getTest() {
Test t;
std::cout << &t << std::endl; // 0xbfeea75f
return t;
}
int main(int argc, char *argv[])
{
Test t = getTest();
std::cout << &t << std::endl; // also 0xbfeea75f
}