程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 實戰c++中的智能指針unique_ptr系列-- std::unique_ptr的構造(盡量使用C++14中的std::make_unique,而不是new)

實戰c++中的智能指針unique_ptr系列-- std::unique_ptr的構造(盡量使用C++14中的std::make_unique,而不是new)

編輯:C++入門知識

實戰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 
  unique_ptr (unique_ptr&& x) noexcept;

move from auto_ptr (8)  
template 
  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 d;
    std::unique_ptr u1;
    std::unique_ptr u2(nullptr);
    std::unique_ptr u3(new int);
    std::unique_ptr u4(new int, d);
    std::unique_ptr u5(new int, std::default_delete());

    std::unique_ptr u8(std::auto_ptr(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 d;
    std::unique_ptr u1;
    std::unique_ptr u2(nullptr);
    std::unique_ptr u3(new int);
    std::unique_ptr u4(new int, d);
    std::unique_ptr u5(new int, std::default_delete());

    std::unique_ptr u8(std::auto_ptr(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 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 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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved