实战c++中的智能指针unique_ptr系列-- std::unique_ptr的构造(尽量使用C++14中的std::make_unique,而不是new)

来源:互联网 发布:linux网桥作用 编辑:程序博客网 时间:2024/05/21 21:41

上篇博客算是unique_ptr的一个开篇,就是简单说说为何要使用unique_ptr,与传统指针相比,智能指针的优势而已。

现在就从构造开始说起!

看看这些构造方法:

default (1) constexpr unique_ptr() noexcept;from null pointer (2)   constexpr unique_ptr (nullptr_t) noexcept : unique_ptr() {}from pointer (3)    explicit unique_ptr (pointer p) noexcept;from pointer + lvalue deleter (4)   unique_ptr (pointer p,    typename conditional<is_reference<D>::value,D,const D&> del) noexcept;from pointer + rvalue deleter (5)   unique_ptr (pointer p,    typename remove_reference<D>::type&& del) noexcept;move (6)    unique_ptr (unique_ptr&& x) noexcept;move-cast (7)   template <class U, class E>  unique_ptr (unique_ptr<U,E>&& x) noexcept;move from auto_ptr (8)  template <class U>  unique_ptr (auto_ptr<U>&& x) noexcept;copy (deleted!) (9) unique_ptr (const unique_ptr&) = delete;

下面就是各个构造unique_ptr的方法:
先看看1 2 3 4 5 8

#include <iostream>#include <memory>int main() {    std::default_delete<int> d;    std::unique_ptr<int> u1;    std::unique_ptr<int> u2(nullptr);    std::unique_ptr<int> u3(new int);    std::unique_ptr<int> u4(new int, d);    std::unique_ptr<int> u5(new int, std::default_delete<int>());    std::unique_ptr<int> u8(std::auto_ptr<int>(new int));    std::cout << "u1: " << (u1 ? "not null" : "null") << '\n';    if (u1 != nullptr)    {        std::cout <<"*u1: "<< *u1 << std::endl;    }    std::cout << "u2: " << (u2 ? "not null" : "null") << '\n';    if (u2 != nullptr)    {        std::cout << "*u2: " << *u2 << std::endl;    }    std::cout << "u3: " << (u3 ? "not null" : "null") << '\n';    if (u3 != nullptr)    {        std::cout << "*u3: " << *u3 << std::endl;    }    std::cout << "u4: " << (u4 ? "not null" : "null") << '\n';    if (u4 != nullptr)    {        std::cout << "*u4: " << *u4 << std::endl;    }    std::cout << "u5: " << (u5 ? "not null" : "null") << '\n';    if (u5 != nullptr)    {        std::cout << "*u5: " << *u5 << std::endl;    }    std::cout << "u8: " << (u8 ? "not null" : "null") << '\n';    if (u8 != nullptr)    {        std::cout << "*u8: " << *u8 << std::endl;    }    return 0;}输出如下:u1: nullu2: nullu3: not null*u3: -842150451u4: not null*u4: -842150451u5: not null*u5: -842150451u8: not null*u8: -842150451

分析可以看出构造函数1 2两个构造方法等价,就是nullptr, 而其他的都是垃圾值。

构造函数3 也许是我们最熟悉的 形如 int* p = new int;

这里的构造函数4 5都用到了一个std::default_delete,这个是什么鬼?
std::default_delete is the default destruction policy used by std::unique_ptr when no deleter is specified.
1) The non-specialized default_delete uses delete to deallocate memory for a single object.
2) A partial specialization for array types that uses delete[] is also provided.

构造函数8 就是从其他智能指针进行构造unique_ptr.

接下来就剩下构造方法6和7个,都使用了std::move语义,我们加上,进行演示:

#include <iostream>#include <memory>int main() {    std::default_delete<int> d;    std::unique_ptr<int> u1;    std::unique_ptr<int> u2(nullptr);    std::unique_ptr<int> u3(new int);    std::unique_ptr<int> u4(new int, d);    std::unique_ptr<int> u5(new int, std::default_delete<int>());    std::unique_ptr<int> u8(std::auto_ptr<int>(new int));    std::cout << "u1: " << (u1 ? "not null" : "null") << '\n';    if (u1 != nullptr)    {        std::cout <<"*u1: "<< *u1 << std::endl;    }    std::cout << "u2: " << (u2 ? "not null" : "null") << '\n';    if (u2 != nullptr)    {        std::cout << "*u2: " << *u2 << std::endl;    }    std::cout << "u3: " << (u3 ? "not null" : "null") << '\n';    if (u3 != nullptr)    {        std::cout << "*u3: " << *u3 << std::endl;    }    std::cout << "u4: " << (u4 ? "not null" : "null") << '\n';    if (u4 != nullptr)    {        std::cout << "*u4: " << *u4 << std::endl;    }    std::cout << "u5: " << (u5 ? "not null" : "null") << '\n';    if (u5 != nullptr)    {        std::cout << "*u5: " << *u5 << std::endl;    }    std::cout << "u8: " << (u8 ? "not null" : "null") << '\n';    if (u8 != nullptr)    {        std::cout << "*u8: " << *u8 << std::endl;    }    std::unique_ptr<int> u6(std::move(u5));    std::cout << "u6: " << (u6 ? "not null" : "null") << '\n';    if (u6 != nullptr)    {        std::cout << "*u6: " << *u6 << std::endl;    }    std::cout << "now, let us see u5:";    std::cout << "u5: " << (u5 ? "not null" : "null") << '\n';    if (u5 != nullptr)    {        std::cout << "*u5: " << *u5 << std::endl;    }    std::unique_ptr<int> u7(std::move(u6));    std::cout << "u7: " << (u7 ? "not null" : "null") << '\n';    if (u7 != nullptr)    {        std::cout << "*u7: " << *u7 << std::endl;    }    std::cout << "now, let us see u6:";    std::cout << "u6: " << (u6 ? "not null" : "null") << '\n';    if (u6 != nullptr)    {        std::cout << "*u6: " << *u6 << std::endl;    }    return 0;}//输出://    u1 : null//  u2 : null//  u3 : not null//  *u3 : -842150451//  u4 : not null//  *u4 : -842150451//  u5 : not null//  *u5 : -842150451//  u8 : not null//  *u8 : -842150451//  u6 : not null//  *u6 : -842150451//  now, let us see u5 : u5 : null//  u7 : not null//  *u7 : -842150451//  now, let us see u6 : u6 : null

这里最最想说明的就是:
u5原来不是null,但是std::move后,u5就变为了空,
u6最开始也不为空,std::move后,u6也变为了空。

还需要强调的一点,就是在对指针进行解除引用的时候,一定要验证指针是否为空,如果指针为空,再进行取值操作,程序就会崩溃。严重的bug。

如果我写到现在就停下来,你又会说我是标题党,但是我不是。
继续:
std::make_unique没有纳入C++11,是C++14的内容:
构造函数有三个:
template< class T, class… Args >
unique_ptr make_unique( Args&&… args );

template< class T >
unique_ptr make_unique( std::size_t size );

template< class T, class… Args >
/* unspecified */ make_unique( Args&&… args ) = delete;

#include <iostream>#include <memory>struct Vec3{    int x, y, z;    Vec3() : x(0), y(0), z(0) { }    Vec3(int x, int y, int z) :x(x), y(y), z(z) { }    friend std::ostream& operator<<(std::ostream& os, Vec3& v) {        return os << '{' << "x:" << v.x << " y:" << v.y << " z:" << v.z << '}';    }};int main(){    // Use the default constructor.    std::unique_ptr<Vec3> v1 = std::make_unique<Vec3>();    // Use the constructor that matches these arguments    std::unique_ptr<Vec3> v2 = std::make_unique<Vec3>(0, 1, 2);    // Create a unique_ptr to an array of 5 elements    std::unique_ptr<Vec3[]> v3 = std::make_unique<Vec3[]>(5);    std::cout << "make_unique<Vec3>():      " << *v1 << '\n'        << "make_unique<Vec3>(0,1,2): " << *v2 << '\n'        << "make_unique<Vec3[]>(5):   " << '\n';    for (int i = 0; i < 5; i++) {        std::cout << "     " << v3[i] << '\n';    }}//输出://make_unique<Vec3>() : {x:0 y : 0 z : 0}//make_unique<Vec3>(0, 1, 2) : {x:0 y : 1 z : 2}//make_unique<Vec3[]>(5) ://{x:0 y : 0 z : 0}//{x:0 y : 0 z : 0}//{x:0 y : 0 z : 0}//{x:0 y : 0 z : 0}//{x:0 y : 0 z : 0}

正如你看到的,make_unique完美的传递了参数给对象的构造函数,从一个原始指针构造出一个std::unique,返回创建的std::unique_ptr。这个形式的函数不支持数组和定制删除器

同直接使用new相比,make函数减小了代码重复,提高的异常安全,并且对于std::make_shared和std::allcoated_shared,生成的代码会更小更快。

此时,可以参考博客http://blog.csdn.net/coolmeme/article/details/43405155

0 0
原创粉丝点击