[C++] 不要在建構函式裡呼叫std::shared_from_this()
阿新 • • 發佈:2019-01-04
前段時間在用std::shared_ptr/std::weak_ptr實現thread-safe和memory-safe的觀察者模式(Observer Pattern)的時候,除錯總給我報錯,最後排查了很久,發現是一個非常tricky的小錯誤。
最開始的版本大概是這樣子的:
class Observer;
class Subject {
public:
void registerObserver(std::shared_ptr<Observer> o) = 0;
void removeObserver(const std::shared_ptr<Observer>& o) = 0 ;
void notifyObservers() = 0;
private:
std::vector<std::weak_ptr<Observer>> observers;
};
被觀察的Subject
內部使用容器來儲存weak_ptr
,因為是弱引用,所以不會造成Observer
和Subject
之間的迴圈引用,也就避免了記憶體洩漏。同時weak_ptr::lock()
也能很容易的做到被管理物件的執行緒安全。
但是在Observer
的建構函式中,我的本意是Obeserver
構造之時即註冊到Subject
的觀察列表中,實現如下:
class Observer : std ::enable_shared_from_this<Observer>{
public:
Observer(std::shared_ptr<Subject>& sbj){
sbj->registerObserver(std::shared_from_this());
//...
}
//...
}
看似想法很美好,甚至都能取一個ORIC(Observer-Registration-Is-Construction)
的新名詞了,模仿RAII
,手動滑稽。
但是當測試的時候老是給我報錯,最後定位到Observer
在
Observer
的建構函式未執行完畢之前,this
指標都是不存在的,或者說是一個殘廢的指標物件,那麼怎麼能呼叫std::shared_from_this()
來獲得一個包裹this
指標的智慧指標物件呢!!!
可以說是肥腸搞笑又低階的錯誤了。。。。。。。。。
那麼Observer
的註冊也只能手動進行了。無礙,只是不那麼優雅罷了。
Anyway,std::enable_shared_from_this & std::shared_from_this
是非常好的管理this
指標的方法(如果你有需要的話)。只要不在建構函式裡瞎呼叫就行了。