上篇博客算是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