嗨我很少怀疑与堆变量...
我想编写如下函数 - >
struct test
{
int x;
int y;
};
test* fun()
{
test *ptr = new test;
return ptr;
}
我怀疑是一个堆变量一旦超出范围就会丢失它的值。
肯定存在内存泄漏。(因为堆变量未被删除。)
那么我该如何设计这种功能呢。
答案 0 :(得分:4)
动态分配的对象(您称之为堆变量)不会在创建它们的范围结束时被销毁。这就是动态分配的重点。虽然test
对象是动态分配的,但指针ptr
不是 - 当它超出范围时 将被销毁。但那没关系!您将指针的值复制到函数之外,此副本仍指向test
对象。 test
对象仍在那里。你写的这个函数很好,但它的风格并不是很好。
是的,如果没有人在指向您创建的delete
对象的指针上test
,则会发生内存泄漏。这是返回像这样的原始指针的问题。您必须信任调用者delete
您正在创建的对象:
void caller()
{
test* p = fun();
// Caller must remember to do this:
delete p;
}
一种常见的C风格的方式(在C ++中绝对不推荐)是拥有create_test
和destroy_test
对函数。这仍然对调用者负责:
void caller()
{
test* p = create_test();
// Caller must remember to do this:
destroy_test(p);
}
解决此问题的最佳方法是不使用动态分配。只需在堆栈上创建一个test
对象,然后将其复制(或移动)出函数:
test fun()
{
test t;
return t;
}
如果您需要动态分配,那么您应该使用智能指针。具体来说,unique_ptr
类型就是您想要的类型:
std::unique_ptr<test> fun()
{
return std::unique_ptr<test>(new test());
}
然后,调用函数可以处理unique_ptr
,而不必担心对其执行delete
。当unique_ptr
超出范围时,它会自动delete
您创建的test
对象。但是,如果调用者希望其他函数具有该对象,则调用者可以将其传递到其他地方。
答案 1 :(得分:2)
您没有返回堆变量,而是返回一个堆栈变量的值,该变量包含指向堆的指针。堆栈变量超出范围;指针指向的内存在堆中 - 它永远不会超出范围。
除非您释放来电者的内存,否则会有内存泄漏。
答案 2 :(得分:1)
我怀疑的是,当一个堆变量超出范围时它会返回它的值。
不用担心,因为你正在通过值来重复指针;因此指针将超出范围,但由于您返回它指向的内存,因此没有内存泄漏(只有我们可以依赖调用者才能删除它)。
但是,如果我们通过引用返回了指针,那么我们就会遇到问题:
test*& fun() // note the & (reference)
{
test *ptr = new test;
return ptr;
}
在这里,您将返回对临时的引用。当变量超出范围时,您将使用不存在的对象。这就是为什么你不能通过引用返回临时的原因。
答案 3 :(得分:0)
我怀疑是一旦它超出范围就会返回一个堆变量,它会失去它的价值。
没有堆变量不像堆栈变量那样超出范围...
肯定存在内存泄漏。(因为堆变量未被删除。)
是的,我们必须释放自己在堆上分配的内存,否则会有内存泄漏......
我建议您阅读与此相关的some tutorial。