2011-03-28 44 views
3

我最近一直在嘗試shared_ptr,並且我碰到了一些奇怪的情況。我想要的是一個模板成員函數,它能夠返回其派生類型的shared_ptr。我正在運行visual studio 2010,它可以訪問一些新的C++ 0x標準,但我認爲boost boost_ptr的行爲類似。shared_ptr從成員函數返回上演版本的問題

這與裸指針正常工作。我剛剛返回了一個dynamic_cast < DerivedClass * >(this)。然而,我有點難過,因爲即使使用enable_shared_from_this,對象也會在函數調用後嘗試刪除自身(這很糟糕)。我可能會接近這個錯誤,但我想研究如何模擬以下(這是我遇到的代碼)的裸指針等效(這是工作)。

//assume we have a virtual function as well. 
class BaseClass : public std::enable_shared_from_this<BaseClass> 
{ 
    .... 
    template<typename DerivedClass> 
    std::shared_ptr<DerivedClass> BaseClass::getThis(){ 
    //I had some assert code here to ensure typeid matched 
    return std::dynamic_pointer_cast<DerivedClass>(shared_from_this()); 
    } 
} 

編輯:看來功能正常工作,該問題是與我是如何使用它。它是壞的,例如執行以下操作:

std::shared_ptr<DerivedClass> p = std::make_shared<DerivedClass>(); 
p->getType<DerivedClass>->someOtherFunctionOnlyInTheDerivedClass(); 

這不是一個問題:

std::shared_ptr<BaseClass> p = std::make_shared<DerivedClass>(); 
p->getType<DerivedClass>->someOtherFunctionOnlyInTheDerivedClass(); 

我不能完全肯定,如果它與轉換爲同一類型的問題,或參考計數問題。在任何情況下,我都在做一些愚蠢的事情,並且破壞了,避免了不必要的getType調用,在那個時候,我似乎在使用它的其他任何情況下都能正常工作。也許有人可以準確解釋導致第一個例子與第二個例子一起工作的原因。我會爲該答案分配點數。

+1

這可能與調用位置的代碼有關,顯示實際實例的創建方式,保存位置以及調用getThis()模板的位置。 – 2011-03-28 11:39:07

+0

你是否在調用getThis後分配返回的值?????? – UmmaGumma 2011-03-28 11:44:50

+0

我編輯了我的問題以反映啓示。我不再有問題,一切似乎都能正常工作,但我很好奇究竟是什麼打破了。 – M2tM 2011-03-28 12:04:01

回答

5

爲了擴展斯圖爾特的答案並(可能)解釋你爲什麼崩潰,我最好的猜測是你在stack-alloc'd實例上調用getType。這是使用enable_shared_from_this的主要缺陷。

#include <memory> 

class Base : public std::enable_shared_from_this<Base> 
{ 
public: 
    virtual ~Base() {} 

    template <typename D> 
    std::shared_ptr<D> getType() 
    { 
     return std::dynamic_pointer_cast<D>(shared_from_this()); 
    } 
}; 

class Derived : public Base 
{ 
public: 
    void f() {} 
}; 

int main() 
{ 
    std::shared_ptr<Derived> d = std::make_shared<Derived>(); 
    d->getType<Derived>()->f(); // fine 

    Derived d2; 
    Base* p = &d2; 
    p->getType<Derived()>->f(); // will attempt to delete d2 after f() returns. 

    return 0; 
} 

發生這種情況的原因是因爲d2的引用計數爲零時,它的堆棧。調用shared_from_this會返回一個shared_ptr,將參考計數遞增爲1。一旦這個指針超出了作用域,它就會將其計數遞減到零,然後嘗試刪除實例,當然這個實例在堆棧中。

我能想到的保護自己的唯一方法就是讓所有的構造函數保護或私有,並提供動態分配任何實例的靜態函數,當然返回shared_ptr

+0

重新分配了正確的答案,因爲我懷疑這是發生了什麼事。不知何故,那裏肯定有一個臨時對象。我只打算共享指向這種類型的對象的指針,所以隱藏構造函數將是一件有益的事情。 – M2tM 2011-03-29 02:34:28

+0

是的,+1,好的想法 – 2011-03-29 14:13:09

+0

我以前遇到過這個問題。追查消息來源需要很長時間。高興地分享我的不幸事蹟。 – 2011-03-29 14:51:08

2

對於它的價值,我不會遇到你與以下最低可編譯例子描述(它看起來像你的代碼上面的描述)問題:

#include <memory> 

class Base : public std::enable_shared_from_this<Base> 
{ 
public: 
    virtual ~Base() {} 

    template <typename D> 
    std::shared_ptr<D> getType() 
    { 
     return std::dynamic_pointer_cast<D>(shared_from_this()); 
    } 
}; 

class Derived : public Base 
{ 
public: 
    void f() {} 
}; 

int main() 
{ 
    std::shared_ptr<Derived> d = std::make_shared<Derived>(); 
    d->getType<Derived>()->f(); 
    return 0; 
} 

這是否崩潰了嗎?

+1

我已經使用clang/libC++(-std = C++ 0x)測試了Stuart的代碼,並且它似乎也在那裏工作。我爲Derived :: f()添加了一個打印語句作爲完整性檢查。 – 2011-03-28 13:22:42

+0

奇怪的是,今天早上我已經測試了你最小的例子(我承認我昨天晚上沒有寫一篇,它已經遲到了......通常這是發佈問題的不好時間。)沒有崩潰。但更進一步,我改變了我的真實代碼示例,不再看到崩潰。我不知道發生了什麼,它看起來像我正確地寫了函數開始,也許我以某種方式與我的構建有問題,或者我可能重新創建它錯誤(雖然我不知道如何可以是,我已經縮小了)。 – M2tM 2011-03-28 15:55:36

+0

因爲今天我不能複製這個,你已經花時間去打獵,所以我給你答案。 – M2tM 2011-03-28 15:58:36