返回堆栈变量?

时间:2013-09-22 01:35:06

标签: c++ variables pointers stack heap

所以,我总是对C ++指针有点模糊,而不管其他人被调用了什么。像,

Object* pointer = new Object();

VS

Object notpointer();

我知道指针可能涉及第二个,但基本上它是一个非指针。 (它究竟叫什么?)

此外,我相信对于第一个,你必须致电

delete pointer;
一旦你完成它,在某些时候,对吗?而另一个你不需要担心。我已经读过第一个是在堆上分配的,但第二个是在堆栈上分配的,当方法返回时就消失了。

然而,当你从一个函数返回一些东西(不是一个原始的)时呢?

一个很好的例子写在Should I return std::strings?

std::string linux_settings_provider::get_home_folder() {
    return std::string(getenv("HOME"));
}

通过我之前写的,字符串在堆栈上分配,并且应该在函数返回时释放,对吧?然而没有人对此有任何说法,所以我认为它运作正常。为什么呢?

一般来说,

之间有什么区别
return new std::string("pointer");

return std::string("not-pointer");

另外,假设两者都有效,两者的利弊是什么?

2 个答案:

答案 0 :(得分:11)

当您通过指针返回时,您需要以您显示的方式返回动态分配的对象(即,如果稍后取消引用,则返回指向堆栈对象的指针会导致未定义的行为)。这会产生内存泄漏的可能性,因为正如您所指出的那样,需要明确删除该对象。

另一方面,按值返回(即第二个片段)会导致将从返回的堆栈对象返回的对象复制到接收返回值的对象中:

std::string res = get_home_folder(); // std::string gets copied into res

编译器可以对此进行优化,以避免通过return value optimization进行复制。

答案 1 :(得分:1)

我猜你真的不想写Object notpointer();,因为这实际上声明了一个名为notpointer的函数,返回Object。如果您的意思是Object notpointer;,则相关实体会调用。实际上,值是在堆栈上分配的,或者当碰巧是对象的成员时,嵌入到对象中。

返回任何内容时,返回的实体将被复制或移动到预期实际返回值的位置。一旦构造了返回值,本地对象(即堆栈上的对象)就会超出范围并被销毁。鉴于本地对象无论如何都会消失,编译器可以忽略副本并立即在正确的位置构造对象,即使拷贝构造函数和/或析构函数有副作用。

两个返回语句之间的区别是

  1. 使用new std::string("pointer")时,您将获得在堆上分配的对象,并返回指向该对象的指针。泄漏指针非常容易,最好立即将它放入合适的物体,例如std::unique_ptr<std::string>

    return std::unique_ptr<std::string>(new std::string("pointer"));
    

    这样,指针不会泄露。当然,您还要将返回类型更改为std::unique_ptr<std::string>而不是std::string*。请注意,堆分配通常相当昂贵。

  2. 使用std::string("value")时,只返回一个局部变量。很有可能省略副本,并且返回值立即构建在它应该去的位置。无需任何资源,因为所有涉及的对象都将被自动销毁。没有明确的堆分配,堆栈分配非常快。
  3. 当然,在给定的示例中,std::string实际上需要在两种情况下分配其内部表示。如果返回指针,则保证没有额外的内部分配。另一方面,当返回std::string值并且实际上确实需要复制时,可能需要为复制分配内部存储器。也就是说,当返回大型对象时,可能需要大量内存分配,返回值的方法会冒着需要复制的风险。然而,对于当前的C ++,对象在最坏的情况下被移动,即,没有像C ++ 03中那样关注复制对象。