2016-11-19 511 views
1

正如您所知,由於包含類的shared_pointer尚未存在,因此無法使用來自對象構造函數的std :: enable_shared_from_this和shared_from_this()對。但是,我真的很想要這個功能。我嘗試了我自己的系統,它似乎工作正常。在構造函數中使用shared_from_this()

namespace kp 
{  

template <class T> 
void construct_deleter(T *t) 
{ 
    if(!t->_construct_pself) 
    { 
    t->~T(); 
    } 

    free(t); 
} 

template <class T, typename... Params> 
std::shared_ptr<T> make_shared(Params&&... args) 
{ 
    std::shared_ptr<T> rtn; 
    T *t = (T *)calloc(1, sizeof(T)); 
    t->_construct_pself = &rtn; 
    rtn.reset(t, construct_deleter<T>); 
    t = new(t) T(std::forward<Params>(args)...); 
    t->_construct_pself = NULL; 
    t->_construct_self = rtn; 

    return rtn; 
} 

template <class T> 
class enable_shared_from_this 
{ 
public: 
    std::shared_ptr<T> *_construct_pself; 
    std::weak_ptr<T> _construct_self; 

    std::shared_ptr<T> shared_from_this() 
    { 
    if(_construct_pself) 
    { 
     return *_construct_pself; 
    } 
    else 
    { 
     return _construct_self.lock(); 
    } 
    } 
}; 

} 

任何人都可以發現這個邏輯中的任何缺陷?我基本上使用placement new來在構造函數調用之前爲該類內的shared_ptr指定一個指針。

既然這樣我可以用它作爲這樣:

std::shared_ptr<Employee> emp = kp::make_shared<Employee>("Karsten", 30); 

,並在Employee構造:

Employee::Employee(std::string name, int age) 
{ 
    Dept::addEmployee(shared_from_this()); 
} 

我犯這個相對大的代碼庫之前,我會很感激的一些想法或來自你們的反饋。

謝謝!

+0

你只能通過你自定義的'make_shared'創建這些;如果您嘗試使用任何其他形式的初始化,它將在運行時失敗。只需使用提供創建實例的靜態'create()'函數的標準模式,然後在返回之前執行任何需要'shared_from_this()'的操作。 –

+0

對不起,但我的團隊無法通過此類代碼審覈。你不能想出更簡單和自我記錄的設計嗎?你最終想要解決的問題是什麼?爲什麼傳統方法不能達到這個目標? –

回答

1

我認爲在構造函數中使用shared_from_this()存在語義上的問題。 問題是當拋出一個異常時,沒有有效的對象,但你已經設置了一個共享指針。例如: -

Employee::Employee(std::string name, int age) 
{ 
    Dept::addEmployee(shared_from_this()); 
    if (...) throw std::runtime_error("..."); 
} 

現在Dept將有一個指向這個對象,這是沒有成功創建。

+0

但是,如果我們只在構造函數的最後執行addEmployee,並且確保在析構函數的最開始處執行removeEmployee,那麼這對於「類管理器:公共職員」繼承也起作用。然後,它還會確保在make_shared 調用後,不完整的員工/經理將永遠不會在Dept中。 –

+0

我剛剛注意到,你的代碼有點意外:如果在員工的C'tor中拋出一個異常,這將迫使一個D'Tor調用。但是,如果C'tor拋出,D'OT被調用。 – Gene

+0

你說得對。雖然我仍然需要釋放內存,但我應該真的把調用包含在「if(!t - > _ construct_pself)」或更好的東西中。 我現在要解決這個問題。謝謝。 –