前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++11:unique_ptr 自己定义类似make_shared的make_unique模板函数

C++11:unique_ptr 自己定义类似make_shared的make_unique模板函数

作者头像
10km
发布2022-05-07 10:03:25
1.1K0
发布2022-05-07 10:03:25
举报
文章被收录于专栏:10km的专栏10km的专栏

C++11中的智能指针分为共享型的shared_ptr和独占型的unique_ptr,C++11提供了make_shared函数来创建shared_ptr指针,使用起来更方便,有了make_shared函数,就可以完全摆脱new操作了,可以写出完全没有new/delete的程序。 但是unique_ptr却不同,unique_ptr不像shared_ptr可以通过make_shared方法来创建智能指针,C++11目前还没有提供make_unique函数,在C++14中才会提供make_shared方法类似的make_unique来创建unique_ptr.

make_unique实现

其实要实现make_unique函数并不复杂,创建普通对象指针的代码如下:

代码语言:javascript
复制
#include <type_traits>
#include <memory>
// 支持普通指针
template<typename T,typename ...Args>inline
unique_ptr<T>
make_unique(Args&&...args){
    static_assert(!is_array<T>::value,"T must not be array");
    return unique_ptr<T>(new T(std::forward<Args>(args)...));
}

调用方式

代码语言:javascript
复制
class test_class{
    int a;
    int b;
    public:
    test():a(),b(){}
    test(int a1,int b1):a(a1),b(b1){}
};
auto obj=make_unique<test_class>(2,3);
auto obj1=make_unique<test_class>();

创建数组指针的unique_ptr代码如下:

代码语言:javascript
复制
#include <type_traits>
#include <memory>
// 初始化版本
template<typename T,bool ZERO=true>inline
typename enable_if<ZERO,unique_ptr<T>>::type
make_unique_array(size_t size){
    // T必须是动态数组类型,且不能是定长数组
    static_assert(is_array<T>::value&& extent<T>::value==0,"T must be dynamic array");
    using U=typename remove_extent<T>::type;
    return unique_ptr<T>(new U[size]());
}
//不初始化的版本
template<typename T,bool ZERO=true>inline
typename enable_if<!ZERO,unique_ptr<T>>::type
make_unique_array(size_t size){
    // T必须是动态数组类型,且不能是定长数组
    static_assert(is_array<T>::value&& extent<T>::value==0,"T must be dynamic array");
    using U=typename remove_extent<T>::type;
    return unique_ptr<T>(new U[size]);
}

为了在创建数组时可以选择是否将数组初始化为0,函数分成执行初始化和不初始化的两个版本。 模板参数中增加了一个常量参数ZERO,用于编译期判断。 用到了名为std::enable_if的type_traits,它类似一个if语句,判断ZERO,当ZERO为true时编译器选择第一个版本的函数,反之选择第二个。 enable_if是C++11头文件<type_traits>中的一个类,关于enable_if的用法详细说明参见:

class template <type_traits>std::enable_if

这样以来,虽然代码多了一倍,但是在编译期就选择了不同版本的make_unique_array函数,避免了运行时判断。

调用方式之前的版本差不多,只是将bool参数移到了模板参数<>

代码语言:javascript
复制
    auto test_array=make_unique_array<test_class[],true>(2);

问题来了

以上的办法虽然好,但是却与C++14版本的make_unique在模板参数类型上并不兼容,你为啥知道C++14的make_unique版本是什么样呢?其实我是写完上面的代码在VS2015下编译时,报了个错,

make_unique
make_unique

我这才发现,VS2015已经提供了make_unique 以下是来自VS2015的<memory>头文件中make_unique的实现代码,代码中创建普通对象和数组对象的函数名都是make_unique,与我写的版本不一样,而且微软的版本中也没有区分是否在初始化数组,一律初始化为0。

代码语言:javascript
复制
    // TEMPLATE FUNCTION make_unique
template<class _Ty,
    class... _Types> inline
    typename enable_if<!is_array<_Ty>::value,
        unique_ptr<_Ty> >::type make_unique(_Types&&... _Args)
    {   // make a unique_ptr
    return (unique_ptr<_Ty>(new _Ty(_STD forward<_Types>(_Args)...)));
    }

template<class _Ty> inline
    typename enable_if<is_array<_Ty>::value && extent<_Ty>::value == 0,
        unique_ptr<_Ty> >::type make_unique(size_t _Size)
    {   // make a unique_ptr
    typedef typename remove_extent<_Ty>::type _Elem;
    return (unique_ptr<_Ty>(new _Elem[_Size]()));//作者注:默认数组初始化为0
    }

template<class _Ty,
    class... _Types>
    typename enable_if<extent<_Ty>::value != 0,
        void>::type make_unique(_Types&&...) = delete;

对这么简单的函数VS2015不可能写一个与标准不兼容的,所以如果考虑到与未来的C++14的兼容性,应该使用这个版本。

参照msvc版本代码修改如下:

代码语言:javascript
复制
#if !defined(_MSC_VER)&&__cplusplus<=201103L
namespace std{
// 支持普通指针
template<typename T,typename ...Args>inline
typename enable_if<!is_array<T>::value, unique_ptr<T> >::type
make_unique(Args&&...args){
    return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
// T必须是动态数组类型,且不能是定长数组
template<typename T>inline
typename enable_if<is_array<T>::value&& extent<T>::value==0,unique_ptr<T>>::type
make_unique(size_t size){
    using U=typename remove_extent<T>::type;
    return unique_ptr<T>(new U[size]());
}
template<typename T,typename ...Args>
typename enable_if<extent<T>::value != 0,   void>::type
make_unique(Args&&...)=delete;
}
#endif /* !defined(_MSC_VER)&&__cplusplus<=201103L */
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-11-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • make_unique实现
  • 问题来了
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档