1

嗨,我对堆变量几乎没有疑问......

我想写一个如下的函数->

struct test
{
   int x;
   int y;
};

test* fun()
{
    test *ptr = new test;

    return ptr;
}
  1. 我的疑问是返回一个堆变量,一旦它超出范围就会失去它的价值。

  2. 肯定有内存泄漏。(因为堆变量没有被删除。)

那么我该如何设计这种功能。

4

4 回答 4

4

动态分配的对象(你称之为堆变量)不会在创建它们的范围结束时被销毁。这就是动态分配的重点。虽然test对象是动态分配的,但指针ptr不是 -当它超出范围时它将被销毁不过没关系!您将指针的值复制到函数之外,并且该副本仍指向test对象。test物体还在。您编写的函数很好,但它不是很好的风格。

是的,如果没有人delete对指向test您创建的对象的指针进行操作,则会出现内存泄漏。这是像这样返回原始指针的问题。您必须信任delete您正在创建的对象的调用者:

void caller()
{
  test* p = fun();
  // Caller must remember to do this:
  delete p;
}

执行此操作的常见 C 风格方式(在 C++ 中绝对不推荐)是拥有一create_testdestroy_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但是,如果调用者希望其他函数拥有该对象,则调用者可以将其传递给其他地方。

于 2013-01-27T17:16:37.360 回答
2
  1. 您不是返回堆变量,而是返回一个堆栈变量的值,该堆栈变量包含指向堆的指针。堆栈变量超出范围;指针指向的内存在堆中——它永远不会超出范围。

  2. 除非您在调用者中释放内存,否则将会发生内存泄漏。

于 2013-01-27T17:16:01.877 回答
1

我的疑问是 [that] 返回一个堆变量,一旦它超出范围,它将失去 [se] 它的值。

不用担心,因为您正在按返回指针;因此指针将超出范围,但由于您正在返回它指向的内存,因此没有内存泄漏(只有当我们可以依赖调用者删除它时)。

但是,如果我们通过引用返回指针,那么我们就会遇到问题:

test*& fun() // note the & (reference)
{
    test *ptr = new test;

    return ptr;
}

在这里,您将返回对临时的引用。当变量超出范围时,您将使用不存在的对象。这就是您不能通过引用返回临时对象的原因。

于 2013-01-28T15:45:10.927 回答
0

我的疑问是返回一个堆变量,一旦它超出范围就会失去它的价值。

没有堆变量不会像 go stack 变量那样超出范围......

肯定有内存泄漏。(因为堆变量没有被删除。)

是的,我们必须自己释放在堆上分配的内存,否则会有内存泄漏......

我建议阅读一些与之相关的教程。

于 2013-01-27T18:19:06.707 回答