嗨,我对堆变量几乎没有疑问......
我想写一个如下的函数->
struct test
{
int x;
int y;
};
test* fun()
{
test *ptr = new test;
return ptr;
}
我的疑问是返回一个堆变量,一旦它超出范围就会失去它的价值。
肯定有内存泄漏。(因为堆变量没有被删除。)
那么我该如何设计这种功能。
嗨,我对堆变量几乎没有疑问......
我想写一个如下的函数->
struct test
{
int x;
int y;
};
test* fun()
{
test *ptr = new test;
return ptr;
}
我的疑问是返回一个堆变量,一旦它超出范围就会失去它的价值。
肯定有内存泄漏。(因为堆变量没有被删除。)
那么我该如何设计这种功能。
动态分配的对象(你称之为堆变量)不会在创建它们的范围结束时被销毁。这就是动态分配的重点。虽然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
但是,如果调用者希望其他函数拥有该对象,则调用者可以将其传递给其他地方。
您不是返回堆变量,而是返回一个堆栈变量的值,该堆栈变量包含指向堆的指针。堆栈变量超出范围;指针指向的内存在堆中——它永远不会超出范围。
除非您在调用者中释放内存,否则将会发生内存泄漏。
我的疑问是 [that] 返回一个堆变量,一旦它超出范围,它将失去 [se] 它的值。
不用担心,因为您正在按值返回指针;因此指针将超出范围,但由于您正在返回它指向的内存,因此没有内存泄漏(只有当我们可以依赖调用者删除它时)。
但是,如果我们通过引用返回指针,那么我们就会遇到问题:
test*& fun() // note the & (reference)
{
test *ptr = new test;
return ptr;
}
在这里,您将返回对临时的引用。当变量超出范围时,您将使用不存在的对象。这就是您不能通过引用返回临时对象的原因。
我的疑问是返回一个堆变量,一旦它超出范围就会失去它的价值。
没有堆变量不会像 go stack 变量那样超出范围......
肯定有内存泄漏。(因为堆变量没有被删除。)
是的,我们必须自己释放在堆上分配的内存,否则会有内存泄漏......
我建议阅读一些与之相关的教程。