Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 析构函数导致sigabrt期间的升压信号_C++_Reference Counting_Pure Virtual_Boost Signals_Boost Signals2 - Fatal编程技术网

C++ 析构函数导致sigabrt期间的升压信号

C++ 析构函数导致sigabrt期间的升压信号,c++,reference-counting,pure-virtual,boost-signals,boost-signals2,C++,Reference Counting,Pure Virtual,Boost Signals,Boost Signals2,我开始使用boost::signals2跟踪对象破坏。我写了一个小测试,看看我是否还能在析构函数中使用信号。这似乎奏效了。然后我开始使用它来跟踪引用其他对象的对象列表。我的结构大致如下: 对于结构的简图: 我有两门课:伊莫代尔和伊布洛克。IModel有许多IBlock,而IBlock有一个IModel父对象。但是,有一种特殊的IBlock称为IModelBlock。此块除了其父块外,还有一个参照的IModel。这在某种程度上是iModel之间的“连接器”。我想让IModels知道哪些IModel

我开始使用boost::signals2跟踪对象破坏。我写了一个小测试,看看我是否还能在析构函数中使用信号。这似乎奏效了。然后我开始使用它来跟踪引用其他对象的对象列表。我的结构大致如下:

对于结构的简图:

我有两门课:伊莫代尔和伊布洛克。IModel有许多IBlock,而IBlock有一个IModel父对象。但是,有一种特殊的IBlock称为IModelBlock。此块除了其父块外,还有一个参照的IModel。这在某种程度上是iModel之间的“连接器”。我想让IModels知道哪些IModels在使用它们,所以我实现了一个参考计数系统,该系统使用IModel和IBlock销毁期间发生的信号来跟踪哪些模型在使用另一个模型

我有我的IBlock纯虚拟类(除了析构函数):

我的IModel头(纯虚拟类):

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);
}
ModelBlock::ModelBlock(IModel*parent,长id,boost::shared\u ptr model)
{
//…很多事情发生在父母和模特身上…然后:
//告诉模特我们看到了他们
模型->现在由(此)使用;
}
这就是它变得多毛的地方

我对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());
    }
}
类模型:公共IModel
{
公众:
...
虚拟模型();
...
受保护的:
...
模型置换无效(IModel*模型);
模型块销毁时无效(IBlock*modelBlock);
...
//正在使用的此模型的计数
地图使用计数;
映射模型破坏连接;
std::向量模型块破坏连接;
};
模型::~Model()
{
typedef std::pair modeldisstructionrecord;
BOOST_FOREACH(ModelDestructionRecord记录,此->modelDestructionConnections)
{
record.second.disconnect();
}
BOOST_FOREACH(BOOST::signals2::connection&connection,this->modelBlockDestructionConnections)
{
连接断开();
}
}
void模型::nowUsedBy(IModelBlock*block)
{
if(block->isOrphan())
return;//如果块是孤立的,则实际上没有使用它的模型
if(useCounts.count(block->getParentModel()))
{
//增加此使用计数
useCounts[block->getParentModel()]++;
}
其他的
{
useCounts[block->getParentModel()]=1;
//订阅模型的销毁
modelDestructionConnections[block->getParentModel()]=block->getParentModel()->sigmodelDestruction.connect(boost::bind(&Model::onmodeldestoring,this,_1));
}
//订阅此modelblock的销毁。我们不需要跟踪它,因为modelblock从不指向
//在它的生命周期中,它将指向我们
this->modelBlockDestructionConnections.push_back(block->sigblockDestruction.connect(boost::bind(&Model::onmodelblockDestructions,this,_1));
}
void模型::onModelDestroying(IModel*模型)
{
如果(此->模型破坏连接.计数(模型))
{
此->modelDestructionConnections[model].disconnect();
此->modelDestructionConnections.erase(模型);
}
}
void Model::onmodelblock(IBlock*modelBlock)
{
如果(!this->useCounts[modelBlock->getParentModel())
return;//据我们所知,我们以前从未见过这个modelblock
//减少模型计数
//请注意,即使modelblock的父指针无效,我们也只是将其用作一个值,所以在这里使用它是可以的
此->使用计数[modelBlock->getParentModel()]--;
如果(此->使用计数[modelBlock->getParentModel()]modelDestructionConnections.count(modelBlock->getParentModel())
{
//这种模式不再使用我们
此->modelDestructionConnections[modelBlock->getParentModel()]断开连接();
这->modelDestructionConnections.erase(modelBlock->getParentModel());
}
}
以下是发生的情况

当我使用ModelBlocks创建一组模型,其中包含嵌套的模型时,每件事情都很顺利。然而,我预料到了一些毁灭性的问题,所以我准备迎接一个巨大的断层…它从未出现过。相反,当我让所有模型(以及它们的所有块)开始销毁阶段时,我得到了一个sigabrt,它说它发生在
Model::onmodelblockDistroming
的第一个
if
。我看了看控制台,它说
纯虚拟方法称为
。我以前从未见过这个错误,所以我不确定如何修复它

堆栈跟踪显示,它正在调用~IBlock析构函数,并发出
sigblockDistroming
信号,在10个函数级别之后,该信号最终调用了
onmodelblockDistroming
函数。现在,如果模型被破坏了,它的所有信号都应该被断开(参见
~模型
),我会认为sigblockDistroming会什么也不调用。因此,我可以得出结论,当调用~IBlock析构函数时,该模型仍然存在,并且该对象仍然有效。我99.9%确信我的假设是错误的,因为显然存在问题,但我不确定为什么会发生这种情况或如何解决它。我知道上面有很多代码,但是有人知道我哪里出错了吗

编辑:我感觉它与调用传入
onmodelblockdriming
的IBlock*的成员函数有关,但对象还没有消失(除非,因为它已经通过析构函数进行实际实现,所以只剩下纯虚拟调用)。这就是正在发生的事情吗?由于析构函数位于~IBlock中,因此当它在树的下面那么远的时候,它已经为~ModelBlock调用了析构函数,因此所有实现的函数都不再是可访问的
class IModel
{
public:
    ...
    virtual void nowUsedBy(IModelBlock* block) = 0;
};
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);
}
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());
    }
}