我有以下代码:
#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
,因此在此过程中不会删除/重新创建对象?
这可以避免(显然这段代码不是最佳的)?
答案 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>());