我开始使用boost :: signals2跟踪对象破坏。我写了一个小测试,看看我是否仍然可以在析构函数here中使用信号。它似乎工作。然后我开始使用它来跟踪引用其他对象的对象列表。我的结构或多或少如此:
对于结构的简略图表:http://oi50.tinypic.com/16c8cwn.jpg
我有两个类IModel和IBlock。 IModel有许多IBlock,IBlock有一个IModel父类。但是,有一个特殊的IBlock称为IModelBlock。除了父级之外,该块还有一个引用的IModel。这是IModels之间的“连接器”。我希望IModel知道哪些IModel正在使用它们,所以我实现了一个引用计数系统,该系统使用在IModel和IBlock破坏期间发生的信号来跟踪哪些模型正在使用另一个模型。
我有我的IBlock纯虚拟类(显然除了析构函数):
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(Model)实现定义了以下内容:
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());
}
}
以下是发生的事情
当我使用ModelBlocks在其中创建一组嵌套模型时,每件事情都很好用。但是,我预计会有一些破坏性的问题,所以我支持自己的一个巨大的段错误......它从来没有出现过。相反,当我让所有模型(及其所有模块)开始破坏阶段时,我得到了一个sigabrt,它表示它发生在第一个Model::onModelBlockDestroying
的{{1}}处。我看着控制台,它说if
。我之前从未见过这个错误所以我不确定如何修复它。
堆栈跟踪显示它正在调用~IBlock析构函数并发出pure virtual method called
信号,该信号在10个函数级别最终调用sigBlockDestroying
函数之后。现在,如果模型被破坏,它的所有信号都应该断开连接(参见onModelBlockDestroying
),我认为sigBlockDestroying不会调用任何东西。因此,我可以得出结论,当调用~IBlock析构函数并且对象仍然有效时,模型仍然存在。我99.9%肯定我错了这个假设,因为显然有问题,但我不确定为什么会发生这种情况或如何解决它。我知道上面有很多代码,但是有谁知道我哪里出错了?
~Model
的IBlock *的成员函数有关,但是对象还没有消失(除非,因为它已经通过了析构函数对于实际的实现,它只剩下纯虚拟调用)。那是怎么回事?因为析构函数在~IBlock中,所以当它到达树的那么远时,它已经被称为~ModeBlock的析构函数,所以所有已实现的函数都不再可访问了?
如果我没有足够好地解释,请告诉我,我会澄清。
答案 0 :(得分:0)
当你在析构函数中调用虚函数时,它将无法按预期工作 - 你正在调用基类虚函数(很可能是纯函数)而不是派生类虚函数。
你的解释中有一些缺失,但我怀疑这是相关的。