我開始使用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的析構函數,因此所有實現的函數都不再可訪問?
如果我沒有解釋得不夠好,只是讓我知道,我會澄清。