删除 std::shared_ptr 时出现标量删除错误
Scalar deleting error when deleting std::shared_ptr
我想知道如何删除我的块 class 的 children。我试着用原始指针来做。我不知道为什么,但它没有用。我收到标量删除错误。我现在尝试用 std::shared_ptr 来做到这一点。我也没有工作。我正在删除 children 与:
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);
因此,您会尝试删除该对象两次,这会导致未定义的行为。
首先:你需要shared指针吗?考虑使用 unique_ptr
作为一种不易出错的想法(如果只有一个指针对象拥有所有权,则更容易理解谁以及何时销毁基础对象)。
接下来,永远不要在这种情况下使用原始指针:只有当您不 store/delete 对象时才可以使用原始指针。并且肯定不要用已经存储在其中一个中的东西创建智能指针。
如果block
指向数组代码,这个代码是非法的,因为对于new[]
你必须调用delete[]
,而std::shared_ptr<Block>
会调用delete
.之后堆将被破坏,进一步的操作可能会失败。如果 blocks
指向数组的一个元素,也会发生同样的情况。如果 blocks
指向不在堆中的对象,也会导致错误。
一般来说,删除传递给函数的指针是个坏主意。不能保证指针是 new 返回的指针,即使它是:by which new?
要为数组创建强引用计数器,您必须使用 std::shared_ptr<Block[]>
,但通常最好使用某种容器。
在共享指针数组中查找指针对象的值:
auto it = std::find_if( children.begin(), children.end(), [=](auto& el) {
return el.get() == block;
});
如果children
不是静态的(那不是某种工厂),那么析构函数代码是完全多余的。在调用 ~Block()
之后,将调用 Block
的每个成员的析构函数,包括将释放其资源并调用每个指针的析构函数的集合,这将调用每个 Block
的析构函数.
一旦指针被赋予 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。
你搜索child就是这个问题。传入一个原始指针,你为它创建一个新的所有者。如果该指针是 child,则它已被拥有。您不得在将原始指针提供给共享指针后从它们创建共享指针。
此外,您为 Block 显示的析构函数没有错,但完全没有必要。您在那里编写的所有代码都会自动发生。块被破坏,它破坏了它持有的向量(因此不需要清除它。)向量破坏了它的元素,所以它持有的共享指针也被清理了。
我想知道如何删除我的块 class 的 children。我试着用原始指针来做。我不知道为什么,但它没有用。我收到标量删除错误。我现在尝试用 std::shared_ptr 来做到这一点。我也没有工作。我正在删除 children 与:
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);
因此,您会尝试删除该对象两次,这会导致未定义的行为。
首先:你需要shared指针吗?考虑使用 unique_ptr
作为一种不易出错的想法(如果只有一个指针对象拥有所有权,则更容易理解谁以及何时销毁基础对象)。
接下来,永远不要在这种情况下使用原始指针:只有当您不 store/delete 对象时才可以使用原始指针。并且肯定不要用已经存储在其中一个中的东西创建智能指针。
如果block
指向数组代码,这个代码是非法的,因为对于new[]
你必须调用delete[]
,而std::shared_ptr<Block>
会调用delete
.之后堆将被破坏,进一步的操作可能会失败。如果 blocks
指向数组的一个元素,也会发生同样的情况。如果 blocks
指向不在堆中的对象,也会导致错误。
一般来说,删除传递给函数的指针是个坏主意。不能保证指针是 new 返回的指针,即使它是:by which new?
要为数组创建强引用计数器,您必须使用 std::shared_ptr<Block[]>
,但通常最好使用某种容器。
在共享指针数组中查找指针对象的值:
auto it = std::find_if( children.begin(), children.end(), [=](auto& el) {
return el.get() == block;
});
如果children
不是静态的(那不是某种工厂),那么析构函数代码是完全多余的。在调用 ~Block()
之后,将调用 Block
的每个成员的析构函数,包括将释放其资源并调用每个指针的析构函数的集合,这将调用每个 Block
的析构函数.
一旦指针被赋予 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。
你搜索child就是这个问题。传入一个原始指针,你为它创建一个新的所有者。如果该指针是 child,则它已被拥有。您不得在将原始指针提供给共享指针后从它们创建共享指针。
此外,您为 Block 显示的析构函数没有错,但完全没有必要。您在那里编写的所有代码都会自动发生。块被破坏,它破坏了它持有的向量(因此不需要清除它。)向量破坏了它的元素,所以它持有的共享指针也被清理了。