假设我具有以下结构:
struct Foo
{
int val;
};
struct Test
{
Foo *bar;
};
我想创建一个Test
结构:
Test get_test()
{
Test test;
Foo foo;
foo.val = 10;
test.bar = &foo;
cout << "INIT: " << test.bar->val << endl;
return test;
}
int main()
{
Test test = get_test();
cout << "AFTER: " << test.bar->val << endl;
return 0;
}
输出如下:
INIT: 10
AFTER: 32723
我试图以不同的方式做到这一点:
Test get_test()
{
Test test;
Foo *foo;
foo->val = 10;
test.bar = foo;
cout << "INIT: " << test.bar->val << endl;
return test;
}
但这给了我SIGSEGV (Address boundary error)
据我有限的理解,我相信这是因为get_test()
中的foo
是一个临时变量,因此该引用没有任何意义。如何正确执行此操作?
答案 0 :(得分:1)
您处在正确的轨道上。在您的第一个示例中,一旦get_test
返回,foo
就不存在了,访问该地址是未定义的行为。第二次尝试也会发生同样的情况,但是问题出在get_test
本身。您声明了Foo* foo;
,但从未将其分配给任何内容,这意味着变量foo
指向某个随机地址。访问它是未定义的行为。
将此作为您的get_test
功能:
Test get_test()
{
Test test;
Foo *foo = new Foo();
foo->val = 10;
test.bar = foo;
cout << "INIT: " << test.bar->val << endl;
return test;
}
在这里,我们用foo
分配new
,所以它分配在堆上,并且将一直保留到您在其上调用delete
为止。这意味着一旦完成,您需要确保delete
,否则会出现内存泄漏。在c ++ 14中,您也可以使用std::unique_ptr
:
struct Test
{
std::unique_ptr<Foo> bar;
};
{
Test test;
std::unique_ptr<Foo> foo = std::make_unique<Foo>();
foo->val = 10;
test.bar = std::move(foo);
cout << "INIT: " << test.bar->val << endl;
return test;
}
std::unique_ptr
将负责删除foo
(一旦超出范围(test
被销毁)),并且您不必担心内存泄漏(但是您可以无法复制std::unique_ptr
,因此您必须std::move
)。
std::unique_ptr
自c ++ 11起可用,std::make_unique
自c ++ 14起可用。
您还需要#include <memory>
才能使用它们。
请查看此link,以了解有关堆和堆栈之间区别的更多信息,以及this one,以了解有关std::unique_ptr
和移动语义的更多信息。