【问题标题】:Returning stack variable?返回堆栈变量?
【发布时间】:2013-09-27 04:19:53
【问题描述】:

所以,我一直对 C++ 指针与......无论另一个指针是什么有点模糊。喜欢,

Object* pointer = new Object();

对比

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");

?

另外,假设两者都有效,两者的优缺点是什么?

【问题讨论】:

  • 第二个是函数。
  • 您在这里混合了几个概念。指针只是一个可以保存内存地址的变量。 new std::string 正在执行内存分配和对象构造。这两个东西不一定要一起使用。在现代 C++ 中,您通常不会这样做。
  • 字符串在栈上分配。它没有被释放;它被摧毁了。但是编译器会在销毁之前复制它。

标签: c++ pointers variables heap-memory stack-memory


【解决方案1】:

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

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

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

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

【讨论】:

  • @BenjaminLindley 你是对的,这看起来不对。谢谢!
  • 谢谢!那么,你怎么称呼一个不是指针的变量呢?
  • @Erhannis 正确,第一个 sn -p 中的res 不是指针。
  • move 仍然是不必要的。例如,您可以按值返回命名的不可复制对象(例如 unique_ptr),而无需对它们调用 move。
  • @Erhannis “对象”或“实例”更常见。返回一个对象实例被称为“按值返回”。
【解决方案2】:

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

当返回任何东西时,被返回的实体被复制或移动到预期实际返回值的位置。一旦构造了返回值,本地对象,即堆栈上的对象,就会超出范围并被销毁。鉴于本地对象无论如何都会消失,因此允许编译器删除副本并立即在正确的位置构造对象,即使复制构造函数和/或析构函数有副作用。

你的两个 return 语句之间的区别是

  1. 当使用new std::string("pointer") 时,您会在堆上分配一个对象并返回一个指向该对象的指针。该指针很容易泄漏,最好立即将其放入合适的对象中,例如std::unique_ptr<std::string>:

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

    这样,指针就不会泄露。当然,您也可以将返回类型更改为std::unique_ptr&lt;std::string&gt;,而不是std::string*。请注意,堆分配通常相当昂贵。

  2. 使用std::string("value") 时,您只需返回一个局部变量。副本很有可能会被忽略,并且返回值会立即在它应该去的位置构造。无需照顾任何资源,因为所有涉及的对象都将自动销毁。没有显式的堆分配,堆栈分配非常快。

当然,在给定的示例中,std::string 实际上需要在两种情况下分配其内部表示。如果返回指针,则保证没有额外的内部分配。另一方面,当返回 std::string 值并且确实需要复制时,可能需要为复制分配内部内存。也就是说,当返回可能需要大量内存分配的大型对象时,返回值的方法存在需要复制它的风险。然而,在当前的 C++ 中,对象在最坏的情况下会被移动,也就是说,复制对象的问题不像在 C++03 中那样多。

【讨论】:

  • 对不起;我假设由于std::string text("notpointer"); 为std::string 调用了1 参数构造函数,Object obj(); 为Object 调用了0 参数构造函数。显然不是。
猜你喜欢
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-14
  • 2019-06-15
  • 2011-04-13
  • 2020-10-27
  • 2015-02-09
相关资源
最近更新 更多