删除std::shared_ptr时出现标量删除错误



我正在尝试了解如何删除Block类的子级。我试着用原始指针来做。我不知道为什么,但它不起作用。我得到标量删除错误。我现在尝试使用std::shared_ptr来完成此操作。我工作不太好。我用移除孩子

void Block::remove(Block* block)
{
std::shared_ptr<Block> ptr(block);
auto it = std::find(children.begin(), children.end(), ptr);
if (it != children.end())
{
*it = NULL;
children.erase(it);
}
}

块删除器是:

Block::~Block()
{
for (auto& child : this->children)
{
child = NULL;
}

if (!this->children.empty())
this->children.clear();
}

根据调试过程,找到ptr变量,然后将其删除。在删除所有内容的时候,直到最后一行,我得到了标量删除错误。仅供记录:children变量的类型为std::vector<std::shared_ptr<Block>>

编辑:完整代码如下:https://github.com/DragonGamesStudios/Ages-of-Life.所有块函数都在AOLGuiLibrary/source/block.cpp 中定义

您将shared_ptr与原始指针混合,这是一种糟糕的做法。如果我理解正确的话,你将块存储在共享指针的向量中,这意味着这个向量对这些对象拥有所有权。当你用一个原始指针创建一个额外的shared_ptr时,你就创建了另一个拥有同一对象所有权的对象:

std::shared_ptr<Block> ptr(block);

因此,您将尝试删除该对象两次,这将导致未定义的行为。

首先:您需要共享指针吗?考虑使用unique_ptr作为一个不太容易出错的想法(如果只有一个指针对象拥有所有权,那么更容易理解谁以及何时会破坏底层对象(。

接下来,千万不要在这种情况下使用原始指针:只有在不存储/删除对象时,才可以使用原始指针。当然,不要用已经存储在其中一个指针中的东西创建智能指针。

一旦一个指针被赋予一个shared_ptr,该shared_ptr就拥有它。您再也不能将该指针赋予另一个共享指针。

int * ptr = new int(1234);
{
std::shared_ptr<int> shp1(ptr); // shp1 owns ptr
std::shared_ptr<int> shp2(ptr); // shp2 owns ptr ???
}
// at this point ptr has been deleted twice

注意:最好不要使用new,而是调用std::make_shared,并且一开始就不要给shared_ptr提供原始指针。

你正在做什么来寻找一个孩子正是这个问题。传入一个原始指针,你就为它创建了一个新的所有者。如果该指针是子指针,那么它就已经被拥有了。在将原始指针提供给共享指针后,不能从原始指针创建共享指针。

此外,您为Block显示的析构函数没有错,但它完全没有必要。你在那里编码的所有内容都会自动发生。块被破坏了,它破坏了它所持有的向量(所以清除它是不必要的。(向量破坏了它的元素,所以它持有的共享指针也被清理了。

如果block指向数组代码,则此代码是非法的,因为对于new[],您必须调用delete[],而std::shared_ptr<Block>将调用delete。在此之后,堆将被破坏,并且进一步的操作可能会失败。如果blocks指向数组的一个元素,也会发生同样的情况。如果blocks指向不在堆中的对象,也会导致错误。

通常,删除传递给函数的指针是个坏主意。不能保证指针是new返回的,即使是:由哪个new返回的?

要为数组创建强引用计数器,必须使用std::shared_ptr<Block[]>,但通常最好使用某种容器。

在共享指针数组中查找指针对象的值:

auto it =  std::find_if( children.begin(), children.end(), [=](auto& el) { 
return el.get() == block; 
});

如果children不是静态的(这不是某种工厂(,那么析构函数代码是完全冗余的。在调用~Block()之后,将调用Block的每个成员的析构函数,包括将释放其资源并对每个指针调用析构函数的集合,该集合将对每个Block调用析构因子。

最新更新