C++14 才加入make_unique , 据说当时忘记实现了。 那么C++11 可以自己实现这个功能:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
关于这个函数,有几点要提的:
1.关于template<typename T, typename... Args>
这里面提到 typename ... ||。详情可以看:https://zh.cppreference.com/w/cpp/language/parameter_pack
总结一下:
模板参数包是接受零个或多个模板参数(非类型、类型或模板)的模板参数。函数参数包是接受零个或多个函数参数的函数参数。具有至少一个参数包的模板称为可变参数模板。
2. 为什么需要实现make_unique(参照 effective modern c++ 第21条),make系列有一些好处。
除了填补make_shared 已经实现了,便于使用外。 还有如下原因:
a.避免重复的冗余,因为new 版本书写了两次类型(Widget),源代码中的重复会导致目标代码笼肿。
b. 避免有可能发生的内存泄漏。
c. 使用make系列,可以让编译器有机会优化出更小更快的代码。
如下:
//1.new版本和 make_unique 版本
std::unique_ptr<Widget> ptr2(new Widget);
std::unique_ptr<Widget> ptr1(make_unique<Widget>());
//2. 使用new版本在函数调用中可能存在的问题。
void processWidget(std::shared_ptr<Widget> spw, int priority);//声明
void processWidget(std::shared_ptr<Widget> (new Widget), computePriority());//new 调用
/*函数的参数调用顺序是不确定的。倘若调用顺序如:
1.Widget tmpW = new Widget
2.computerPriority()
3.share_ptr<widget> tmpPtr = tmp;
假设在函数执行到computerPriority()时,异常 那么则会出现内存泄漏。
因为,tmpW并没有让share_ptr接管到, 这种错误是很隐晦的。*/
3 .补充第二点,有些情况是不能使用make系列的。
1) 当需要用到自定义析构函数时,如:
std::shared_ptr<Widget> spw(new Widget,widgetDeleter);
2)当想使用std::initializer_list 型别的形参来重载构造函数,如:
auto initList={10,20};
auto spv=std::make_shared<std::vector<int>>(initList);
4.对于std::shared_ptr ,不建议使用make系列函数的额外场景包括(比较少的情况):
a) 自定义内存管理类
b) 内存紧张的系统,非常大的对象,以及存在比指涩到相同对象的std::shared_ptr生存期更久 的std::weak_ptr;