【问题标题】:C++ what happens when function returns vector<shared_ptr<>>?C++ 当函数返回vector<shared_ptr<>>时会发生什么?
【发布时间】:2017-05-29 19:37:35
【问题描述】:

我有以下代码:

#include <iostream>
#include <memory>
#include <vector>

class Test
{
public:
    Test() {}
    ~Test() { std::cerr << "Delete\n"; }
};

std::vector<std::shared_ptr<Test>> makeList()
{
    std::vector<std::shared_ptr<Test>> list;
    list.push_back(std::make_shared<Test>(Test()));

    return std::move(list);
}

int main(int argc ,char **argv)
{

    std::vector<std::shared_ptr<Test>> list;
    std::cerr << "Before\n";
    list = makeList();
    std::cerr << "After\n";

    return 0;
}

我使用的编译器:

clang++ -std=c++14 -o ptr ptr.cpp

输出是:

Before
Delete
After
Delete

我的问题是:为什么makeList 函数中有一个对象被删除?我的假设是函数中的list 将从main 移动到list,因此在此过程中不会删除/重新创建任何对象?

这可以避免吗(显然这段代码不是最优的)?

【问题讨论】:

  • 您使用Test() 创建一个临时的Test 对象。然后由make_shared 制作一份副本,然后临时文件被销毁。你可能想要std::make_shared&lt;Test&gt;()
  • 出于效率原因,return std::move(list); 应该是 return list;
  • ^^ 这个。 OP:如果您的编译器没有对此发出警告,也许是时候获得更好的编译器(或打开警告)。 std::move() 这里禁止返回值优化。最新版本的 clang 可以对此发出警告。

标签: c++ c++11 c++14 shared-ptr move-semantics


【解决方案1】:

2 变化:

std::vector<std::shared_ptr<Test>> makeList()
{
    std::vector<std::shared_ptr<Test>> list;

    // make_shared does not need a copy of an object, just constructor arguments
    list.push_back(std::make_shared<Test>());

    // return std::move(list) will defeat RVO. Never do that.    
    return list;
}

所以,重要的部分是:

    list.push_back(std::make_shared<Test>(Test()));

->

    list.push_back(std::make_shared<Test>());

只是为了澄清一下,因为我今天也有同样的情况,但我看不出有什么不同。

【讨论】:

  • 好的,谢谢,我刚刚尝试了这个动作,因为我认为强制它会有所作为,但我尝试了这两个选项,所以实际上问题来自于我在拨打电话时创建了一个临时对象到make_shared。非常感谢。
【解决方案2】:
list.push_back(std::make_shared<Test>(Test()));

这里临时是用Test() 创建的。然后调用 Test 的复制 c-tor 并销毁临时文件。这是第一个析构函数调用。

list被销毁时,第二个析构函数调用出现在程序末尾。

避免临时创建的正确形式是:

list.push_back(std::make_shared<Test>());

除了你不应该使用std::move返回值,因为在这种情况下编译器无法应用返回值优化

【讨论】:

    【解决方案3】:

    list.push_back(std::make_shared&lt;Test&gt;(Test())); 行生成一个临时的Test,然后将其移动到由std::make_shared&lt;T&gt; 构造的实际Test。这个临时的然后被销毁。

    std::make_shared&lt;T&gt; 要求在构造T 时使用参数。对于默认构造的T,只需不提供任何参数。

    在这种情况下,正确的用法是:

    list.push_back(std::make_shared<Test>());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-06
      • 1970-01-01
      • 2022-01-07
      相关资源
      最近更新 更多