之前博客《[淺析C++中的智能指針](http://blog.csdn.net/wangshubo1989/article/details/48337955 "智能指針")》講訴了一些智能指針的東西,可以幫助我們更加方便高效的使用指針,但是凡事都不會很完美。即使你使用智能指針代替了傳統的指針,在實戰中你還是會遇到很多的坑兒。
現在,就分幾個方面:
首先為了簡化代碼,進行了一些定義:
~~~
class Test
{
public:
Test():m_value(0) { std::cout << "Test::Test" << std::endl; }
~Test() { std::cout << "Test::~Test destructor" << std::endl; }
int m_value;
};
typedef std::auto_ptr<Test> TestAutoPtr;
typedef std::unique_ptr<Test> TestUniquePtr;
typedef std::shared_ptr<Test> TestSharedPtr;
~~~
**為什么auto_ptr 被棄用?**
auto_ptr 是第一個智能指針。 但是為什么會被棄用呢?看看一個簡單的例子
~~~
void doSomethig(TestAutoPtr myPtr) {
myPtr->m_value = 11;
}
void AutoPtrTest() {
TestAutoPtr myTest(new Test());
doSomethig(myTest);
myTest->m_value = 10;
}
~~~
編譯上面的代碼并試著運行,會有什么樣的結果呢?答案是在doSomething執行結束后程序崩潰! 我們可以推斷,在doSomething 中,引用計數增加了,但是auto_ptr沒有這樣的功能。
所以我們應該傳遞智能指針的引用。但是對于更加復雜的對象,我們就會失去控制。
**為什么 unique_ptr 很好用?**
幸運的是,我們有新的智能指針。在之前的例子中,我們使用std::unique_ptr 代替auto_ptr 這時候,我們會得到編譯錯誤,而不是運行時期的錯誤。因為,我們不能傳遞一個unique_ptr給另一個函數。
但是為了可以傳遞,我們可以使用move把智能指針的所有權進行轉移,代碼如下:
~~~
doSomethig(std::move(myTest));
~~~
**如何使用數組和unique_ptr 聯系在一起?**
首先我們要明確的是,下面的代碼是致命的:
~~~
std::unique_ptr<int> p(new int[10]); // will not work!
~~~
之所以說上面的代碼是致命的是因為可以編譯通過。但是當資源被釋放掉的時候,只有delete被調用,而不是delete[]。所以,我們如何確保delete[] 被調用呢?
你應該這么干:
~~~
std::unique_ptr<int[]> p(new int[10]);
p[0] = 10;
~~~
對于上面的例子,我們可以這么干:
~~~
std::unique_ptr<Test[]> tests(new Test[3]);
~~~
這樣就會得到我們期望的輸出:
Test::Test
Test::Test
Test::Test
Test::~Test destructor
Test::~Test destructor
Test::~Test destructor
**為什么使用shared_ptr ?**
通過引用計數來實現shared_ptr ,所以我們這么干:
~~~
std::shared_ptr<Test> sp(new Test());
std::shared_ptr<Test> sp2 = std::make_shared<Test>();
~~~
得到這樣的輸出:
Test::Test
Test::Test
Test::~Test destructor
Test::~Test destructor
**如何使用數組和shared_ptr 聯系在一起?**
~~~
std::shared_ptr<Test> sp(new Test[2], [](Test *p) { delete [] p; });
~~~
**如何把智能指針傳遞給函數?**
看代碼:
~~~
void testSharedFunc(std::shared_ptr<Test> sp) {
sp->m_value = 10;
}
void testSharedFuncRef(const std::shared_ptr<Test> &sp) {
sp->m_value = 10;
}
void SharedPtrParamTest() {
std::shared_ptr<Test> sp = std::make_shared<Test>();
testSharedFunc(sp);
testSharedFuncRef(sp);
}
~~~
只有testSharedFunc 會增加引用計數。 也就是說傳遞ref沒有增加引用計數,那么到底是哪種方式好呢?
視情況而定!
**如何對智能指針進行類型轉換?**
看看這個代碼:
~~~
class BaseA
{
protected:
int a{ 0 };
public:
virtual ~BaseA() { }
void A(int p) { a = p; }
};
class ChildB : public BaseA
{
private:
int b{ 0 };
public:
void B(int p) { b = p; }
};
~~~
毫無疑問,我可以創建一個指向A的智能指針,并初始化為B:
~~~
std::shared_ptr<BaseA> ptrBase = std::make_shared<ChildB>();
ptrBase->A(10);
~~~
但是如何強制轉換呢,把ptrBase指向B呢?你可能這樣嘗試:
~~~
ChildB *ptrMan = dynamic_cast<ChildB *>(ptrBase.get());
ptrMan->B(10);
~~~
成功了,但是代價是你只獲得了一個普通指針。智能指針的引用計數并沒有增加。所以更好的辦法就是使用智能指針的轉換方法:
~~~
std::shared_ptr<ChildB> ptrChild = std::dynamic_pointer_cast<ChildB>(ptrBase);
if (ptrChild)
{
ptrChild->B(20);
std::cout << "use count A: " << ptrBase.use_count() << std::endl;
std::cout << "use count B: " << ptrChild.use_count() << std::endl;
}
~~~
通過使用std::dynamic_pointer_cast 你會得到一個shared pointer.
**結語:**
智能指針沒有用,但是我們應該更加謹慎的使用它們!
stay foolish stay hungry!
- 前言
- deprecated關鍵字
- 指針(內存泄露)
- 頭文件相互包含(Compiler error C2653: not a class or namespace name)
- 獲取一張圖片的width和height
- This function or variable may be unsafe.
- 智能指針陷阱
- string中的c_str()陷阱
- wstring與string的轉換
- windows下chrome瀏覽器插件不能安裝
- 重定義關鍵字
- 正確釋放vector的內存
- 獲取設備環境HDC
- 抽象類不能實例化對象(但是你明明定義的不是抽象類)
- 重載賦值運算符的自我賦值
- 程序中的變量未初始化
- 成對使用new和delete時要采取相同的形式
- 意想不到的除數為零
- map的初始化(插入數據)
- 正則表達式截取字符串
- 捕獲窗口之外的鼠標消息(鉤子還是??)
- 類中的靜態成員變量(static or const static)
- 有if就要有else(一定成對)
- map查找結果處理
- 使用using namespace std的壞習慣
- new一個指針數組、以及創建動態二維數組
- 使用太多的全局變量
- 沒有及時break出for循環
- vector使用erase后迭代器變成野指針
- C++函數的默認參數(重新定義默認參數)
- 0xC0000005: 讀取位置 xxx時發生訪問沖突
- std::string初始化、最快速判斷字符串為空
- 你開發的軟件安裝在C盤Program Files (x86)下產生的異常