今天遇到一個錯誤,是關於unique_ptr的get方法的,忽略了。
之前博客是這樣寫get方法的:
其中bar是一個智能指針,p是一個普通指針:
p = bar.get(); 後,bar並非被釋放,也就相當於指針p和智能指針bar共同管理一個對象,所以就*p做的一切,都會反應到bar指向的對象上。
那麼來看今天的代碼:
#include
#include
class Widget {
public:
Widget() { std::cout << "Widget::Widget()" << std::endl; }
virtual ~Widget() { std::cout << "Widget::~Widget()" << std::endl; }
virtual void draw() = 0;
};
class WindowsButton : public Widget {
public:
WindowsButton() = default;
~WindowsButton() = default;
void draw() { std::cout << "WindowsButton" << std::endl; }
};
int main() {
std::unique_ptr w = std::unique_ptr(new WindowsButton());
w.get()->draw();
w->draw();
}
輸出:
Widget::Widget()
WindowsButton
WindowsButton
Widget::~Widget()
就是使用w.get()和直接使用w是一樣的效果!
現在就要玩點花樣了:
#include
#include
class Widget {
public:
Widget() { std::cout << "Widget::Widget()" << std::endl; }
virtual ~Widget() { std::cout << "Widget::~Widget()" << std::endl; }
virtual void draw() = 0;
};
class WindowsButton : public Widget {
public:
WindowsButton() = default;
~WindowsButton() = default;
void draw() { std::cout << "WindowsButton" << std::endl; }
};
int main() {
Widget* w = std::unique_ptr(new WindowsButton()).get();
w->draw();
}
上面的代碼再執行w->draw()的時候會崩潰,why?
首先呢,這麼寫代碼純是吃飽撐的。
智能指針就是幫助我們管理內存的,為何又要賦值給普通指針呢?
好,即使你寫了這樣的代碼,也是對變量生命周期不是很了解:
Widget* w = std::unique_ptr(new WindowsButton()).get();
由於 unique_ptr 擁有對象,所以當unique_ptr 被摧毀的時候,它所指向的對象也會銷毀,所以接下來的w指針指向的是一個已經銷毀的對象,於是調用這個已經銷毀對象的成員函數當然是錯誤的,導致崩潰。
個人覺得,盡量避免使用get方法,既然unique_ptr給我們提供了那麼多的便利條件,我們就不應該铤而走險。
個人還覺得,盡量避免智能指針和普通指針的混合,那樣容易非常的亂,導致內存洩露,導致崩潰。