C ++当函数返回vector <shared_ptr <>&gt;时会发生什么?

时间:2017-01-14 15:05:51

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

我有以下代码:

#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将从list移入main,因此在此过程中不会删除/重新创建对象?

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

3 个答案:

答案 0 :(得分:4)

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

- &GT;

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

只是为了澄清,因为我今天也一样,而且我很难看出差异。

答案 1 :(得分:3)

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

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

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

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

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

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

答案 2 :(得分:2)

list.push_back(std::make_shared<Test>(Test()));生成一个临时Test,然后将其移动到由Test构建的实际std::make_shared<T>中。这个临时性随后被销毁。

std::make_shared<T>要求在构造T时使用参数。对于默认构造的T,不提供任何参数。

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

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