0

我開始使用boost :: signals2跟蹤對象的破壞。我寫了一個小測試來看我是否仍然可以在破壞者here中使用信號。它似乎工作。然後我開始使用它來跟蹤引用其他對象的對象列表。我的結構或多或少像這樣:在造成sigabrt的析構函數中增強信號

對於結構的簡化示意圖:http://oi50.tinypic.com/16c8cwn.jpg

我有兩個類IModel和I塊。 IModel有許多IBlocks,而IBlock有一個IModel父級。但是,有一個特殊的IBlock叫做IModelBlock。除了其父項外,該塊還有一個引用的IModel。這是IModels之間的「連接器」。我希望IModels知道哪些IModel正在使用它們,所以我實現了一個引用計數系統,該系統使用在銷燬IModel和IBlock期間發生的信號來跟蹤哪些模型正在使用另一個模型。

我有我的I塊純虛類(除了析構函數很明顯):

class IBlock 
{ 
public: 
    virtual ~IBlock() { this->sigBlockDestroying(this); } 
    ... 
    boost::signals2::signal<void (IBlock*)> sigBlockDestroying; //raised when the destructor is called 
}; 

我IModelBlock頭(純虛類):

class IModelBlock : public IBlock 
{ 
public: 
    virtual ~IModelBlock() {} 
    ... 
}; 

我IModel頭(純虛類) :

class IModel 
{ 
public: 
    ... 
    virtual void nowUsedBy(IModelBlock* block) = 0; 
}; 

我的IModelBlock構造函數(ModelBlock類)的實現通知一個模型正在使用它:

ModelBlock::ModelBlock(IModel *parent, long id, boost::shared_ptr<IModel> model) 
{ 
    //...lots of stuff happens involving the parent and model...then: 

    //tell the model we see them 
    model->nowUsedBy(this); 
} 

這裏就是它得到毛茸茸

我IModel(模型)的實現定義以下內容:

class Model : public IModel 
{ 
public: 
    ... 
    virtual ~Model(); 
    ... 
protected: 
    ... 
    void onModelDestroying(IModel* model); 
    void onModelBlockDestroying(IBlock* modelBlock); 
    ... 
    //counts for this model being used 
    std::map<IModel*, int> useCounts; 
    std::map<IModel*, boost::signals2::connection> modelDestructionConnections; 
    std::vector<boost::signals2::connection> modelBlockDestructionConnections; 
}; 

Model::~Model() 
{ 
    typedef std::pair<IModel*, boost::signals2::connection> ModelDestructionRecord; 
    BOOST_FOREACH(ModelDestructionRecord record, this->modelDestructionConnections) 
    { 
     record.second.disconnect(); 
    } 
    BOOST_FOREACH(boost::signals2::connection& connection, this->modelBlockDestructionConnections) 
    { 
     connection.disconnect(); 
    } 
} 

void Model::nowUsedBy(IModelBlock *block) 
{ 
    if (block->isOrphan()) 
     return; //if the block is an orphan, there isn't actually a model using it 

    if (useCounts.count(block->getParentModel())) 
    { 
     //increment this use count 
     useCounts[block->getParentModel()]++; 
    } 
    else 
    { 
     useCounts[block->getParentModel()] = 1; 
     //subscribe to the model's destruction 
     modelDestructionConnections[block->getParentModel()] = block->getParentModel()->sigModelDestroying.connect(boost::bind(&Model::onModelDestroying, this, _1)); 
    } 

    //subscribe to this modelblock's destruction. we don't need to track this because modelblocks never point to 
    //other models and so for its lifetime it will point to us 
    this->modelBlockDestructionConnections.push_back(block->sigBlockDestroying.connect(boost::bind(&Model::onModelBlockDestroying, this, _1))); 
} 

void Model::onModelDestroying(IModel *model) 
{ 
    if (this->modelDestructionConnections.count(model)) 
    { 
     this->modelDestructionConnections[model].disconnect(); 
     this->modelDestructionConnections.erase(model); 
    } 
} 

void Model::onModelBlockDestroying(IBlock *modelBlock) 
{ 
    if (!this->useCounts[modelBlock->getParentModel()]) 
     return; //we've never seen this modelblock before as far as we know 

    //decrement the the model count 
    //note that even if the modelblock's parent pointer is invalid, we are just using it for being a value so its ok to use here 
    this->useCounts[modelBlock->getParentModel()]--; 

    if (this->useCounts[modelBlock->getParentModel()] <= 0 && this->modelDestructionConnections.count(modelBlock->getParentModel())) 
    { 
     //we are no longer used by this model 
     this->modelDestructionConnections[modelBlock->getParentModel()].disconnect(); 
     this->modelDestructionConnections.erase(modelBlock->getParentModel()); 
    } 
} 

這裏發生了什麼

當我用n個模型創建一堆模型時,每件事都可以正常工作使用ModelBlocks在他們內部創建模型。但是,我預料到一些破壞的問題,所以我支持自己的一個巨大的segfault ......從來沒有來過。相反,當我將所有模型(及其所有模塊)開始銷燬階段時,我得到一個sigabrt,它表示它發生在Model::onModelBlockDestroying右邊第一個if。我看着控制檯,它說pure virtual method called。我從來沒有見過這個錯誤,所以我不確定如何解決它。

堆棧跟蹤顯示它正在調用〜IBlock析構函數,併發出sigBlockDestroying信號,在10個函數級別最終調用onModelBlockDestroying函數後。現在,如果模型被破壞了,它的所有信號都應該被斷開(見~Model),我認爲sigBlockDestroying什麼也沒有。所以,我可以得出結論:當〜IBlock析構函數被調用並且對象仍然有效時,該模型仍然存在。我99.9%肯定我在這個假設中是錯誤的,因爲顯然存在問題,但我不確定它爲什麼會發生或者如何解決它。我知道它上面有很多代碼,但是有沒有人看到我出錯的地方?

編輯:我有一種感覺,它與調用IBlock的成員函數*傳遞給onModelBlockDestroying,但該對象還沒有消失(除非,因爲它已經通過實際的析構函數實現它只剩下純虛擬調用)。那是怎麼回事?因爲析構函數在〜IBlock中,當它到達樹的下方時,它已經被稱爲〜ModelBlock的析構函數,因此所有實現的函數都不再可訪問?

如果我沒有解釋得不夠好,只是讓我知道,我會澄清。

回答

0

當您在析構函數中調用虛函數時,它將無法按預期工作 - 您正在調用基類虛函數(最可能是純函數)而不是派生類虛函數。

你的解釋有一些缺失,但我懷疑這是相關的。