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

上篇博客算是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::value,D,const D&> del) noexcept;

from pointer + rvalue deleter (5)   
unique_ptr (pointer p,
    typename remove_reference::type&& del) noexcept;

move (6)    
unique_ptr (unique_ptr&& x) noexcept;

move-cast (7)   
template <class U, class E>
  unique_ptr (unique_ptr&& x) noexcept;

move from auto_ptr (8)  
template <class U>
  unique_ptr (auto_ptr&& x) noexcept;

copy (deleted!) (9) 
unique_ptr (const unique_ptr&) = delete;

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

#include 
#include 

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: null
u2: null
u3: not null
*u3: -842150451
u4: not null
*u4: -842150451
u5: not null
*u5: -842150451
u8: 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 
#include 

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 
#include 

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 v1 = std::make_unique();
    // Use the constructor that matches these arguments
    std::unique_ptr v2 = std::make_unique(0, 1, 2);
    // Create a unique_ptr to an array of 5 elements
    std::unique_ptr v3 = std::make_unique(5);

    std::cout << "make_unique():      " << *v1 << '\n'
        << "make_unique(0,1,2): " << *v2 << '\n'
        << "make_unique(5):   " << '\n';
    for (int i = 0; i < 5; i++) {
        std::cout << "     " << v3[i] << '\n';
    }
}

//输出:
//make_unique() : {x:0 y : 0 z : 0}
//make_unique(0, 1, 2) : {x:0 y : 1 z : 2}
//make_unique(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

你可能感兴趣的:(C++)