11

所以,我一直对 C++ 指针与......无论另一个被称为什么都有些模糊。喜欢,

Object* pointer = new Object();

对比

Object notpointer();

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

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

delete pointer;

一旦你完成它,在某个时候,对吧?另一个你不需要担心。我读过第一个分配在堆上,但第二个分配在堆栈上,并在方法返回时消失。

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

一个很好的例子写在我应该返回 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");

?

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

4

2 回答 2

14

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

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

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

编译器可以通过返回值优化对此进行优化以避免复制。

于 2013-09-22T01:48:38.597 回答
3

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

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

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

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

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

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

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

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

于 2013-09-22T01:56:35.570 回答