C++ Unique_ptr 与向量的向量相关
C++ is Unique_ptr pertinent for vectors of vectors
我的情况是我使用构建器来使用工厂为我的项目创建 CombatUnit,如模式所示(请注意我有一个抽象工厂,但我不会无缘无故地将其复杂化).
事实是,我正在创建数组的数组,并且我正在使用 unique_ptr 来防止内存泄漏。
但我找不到我是否过度使用了 smart_pointer,这就是为什么
std::unique_ptr<std::vector<std::unique_ptr<std::vector<std::unique_ptr<CombatObject>>>>>& Builder_FleetsCombatObjects::BuildFleets(const std::vector<const CombatObject::ConstructionOrder_CombatObject>& orders)
{
std::unique_ptr<std::vector<std::unique_ptr<std::vector<std::unique_ptr<CombatObject>>>>> fleets(new std::vector<std::unique_ptr<std::vector<std::unique_ptr<CombatObject>>>>());
Factory_Mechas mFact;
Factory_SpaceShip sFact;
for (auto order : orders)/* No Abstract factory to match schema */
{
if (sFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets->push_back(sFact.CreateSpaceShip(order));
}
else if (mFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets->push_back(mFact.CreateMechas(order));
}
}
return fleets;
}
从我的实际角度来看,它并不过分,即使 smart_pointer 更重更慢(我的意思是一般使用),每个 unique_ptr 都会确保子 smart_pointer将调用“删除器”。
但不知何故,我觉得它不对,就像我不太了解 smartpointer 的工作原理一样。
向量不应该“确保”子向量是“免费的”吗?然后我可以减少到:std::unique_ptr<std::vector<std::vector<std::unique_ptr<CombatObject>>>>&
甚至 std::vector<std::vector<std::unique_ptr<CombatObject>>>
如果 vector 在 c++19 中是内存管理的。
我不太确定我理解的是什么,你能帮我吗?
C++ is Unique_ptr pertinent for vectors of vectors
这由您决定,但只是在没有其他基础结构知识的情况下快速查看代码,我会说这是一种沉重、可怕的代码味道。我会简单地按原样使用矢量。它更轻、更安全、更简单、更快。
指向 STL 容器的指针通常是代码气味的强烈指标,而指向包含指向 STL 容器指针的 STL 容器的指针具有更强烈的代码气味。这根本不会通过审查,我会敦促简化。
拥有指向 STL 容器的指针实际上不应该存在于代码中,除非有一些 class 通过容器指针封装非常特殊的内存管理,但它们不应该逃避 class。即便如此,您也可以管理内存并使用简单的容器值进行重用。
您应该尝试一下值语义!它有助于局部思考,通常可以使代码更简单。
现在是问题的非意见部分。
让我们删除代码中多余的唯一指针,以便更容易解释:
std::vector<std::vector<std::unique_ptr<CombatObject>>>& Builder_FleetsCombatObjects::BuildFleets(const std::vector<const CombatObject::ConstructionOrder_CombatObject>& orders)
{
std::vector<std::vector<std::unique_ptr<CombatObject>>> fleets{};
Factory_Mechas mFact;
Factory_SpaceShip sFact;
for (auto order : orders)/* No Abstract factory to match schema */
{
if (sFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets.push_back(sFact.CreateSpaceShip(order));
}
else if (mFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets.push_back(mFact.CreateMechas(order));
}
}
return fleets;
}
在这段代码中,我们复制并构造了新的向量,并分配了新的唯一指针。
在这里,您的问题将变成:如何确保释放唯一指针的向量向量?
好吧,让我们从看一个整数向量开始:
{
std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
}
// Did we leaked?
这里,我们没有泄露。这是因为 vector 负责分配和释放。它将在推回时释放旧缓冲区,并在向量超出范围时释放。
那么唯一指针呢?
{
std::unique_ptr<int> ptr = std::make_unique<int>(3);
*ptr = 1;
} // Did we leaked?
现在我们泄露了吗?不,那太荒谬了!
现在让我们尝试复制这两种类型:
std::vector<int> vec;
std::unique_ptr<int> ptr = std::make_unique<int>(3);
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
// Copy!
std::vector<int> vec2 = vec;
std::unique_ptr<int> ptr2 = ptr; // Uh oh! Error!
这里如你所见,不能复制唯一指针。复制唯一指针将无法编译。
但是,你可以复制一个向量,那么当你复制一个唯一指针的向量时会发生什么?
std::vector<std::unique_ptr<int>> vec_ptr;
vec_ptr.push_back(std::make_unique<int>(1));
vec_ptr.push_back(std::make_unique<int>(2));
vec_ptr.push_back(std::make_unique<int>(3));
std::vector<std::unique_ptr<int>> vec_ptr2 = vec_ptr; // Error again!
这里还是编译不通过!那是因为要创建缓冲区的副本,您需要复制每个元素。如果无法复制元素,则无法复制向量,因此向量不可复制。
现在由于 vector 完全管理内存,而唯一 ptr 完全管理内存,除非您明确要求唯一指针放弃所有权,否则您不能泄漏任何内存:
std::unique_ptr<int> ptr = std::make_unique<int>(3);
int* raw_owning_pointer = ptr.release();
// Here, I have to delete it myself
现在在您的代码中,无论回推以及唯一指针和向量组合,都没有泄漏!
要真正确保完全没有泄漏,请使用消毒剂或内存调试器(如 valgrind)。
我的情况是我使用构建器来使用工厂为我的项目创建 CombatUnit,如模式所示(请注意我有一个抽象工厂,但我不会无缘无故地将其复杂化).
事实是,我正在创建数组的数组,并且我正在使用 unique_ptr 来防止内存泄漏。 但我找不到我是否过度使用了 smart_pointer,这就是为什么
std::unique_ptr<std::vector<std::unique_ptr<std::vector<std::unique_ptr<CombatObject>>>>>& Builder_FleetsCombatObjects::BuildFleets(const std::vector<const CombatObject::ConstructionOrder_CombatObject>& orders)
{
std::unique_ptr<std::vector<std::unique_ptr<std::vector<std::unique_ptr<CombatObject>>>>> fleets(new std::vector<std::unique_ptr<std::vector<std::unique_ptr<CombatObject>>>>());
Factory_Mechas mFact;
Factory_SpaceShip sFact;
for (auto order : orders)/* No Abstract factory to match schema */
{
if (sFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets->push_back(sFact.CreateSpaceShip(order));
}
else if (mFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets->push_back(mFact.CreateMechas(order));
}
}
return fleets;
}
从我的实际角度来看,它并不过分,即使 smart_pointer 更重更慢(我的意思是一般使用),每个 unique_ptr 都会确保子 smart_pointer将调用“删除器”。
但不知何故,我觉得它不对,就像我不太了解 smartpointer 的工作原理一样。
向量不应该“确保”子向量是“免费的”吗?然后我可以减少到:std::unique_ptr<std::vector<std::vector<std::unique_ptr<CombatObject>>>>&
甚至 std::vector<std::vector<std::unique_ptr<CombatObject>>>
如果 vector 在 c++19 中是内存管理的。
我不太确定我理解的是什么,你能帮我吗?
C++ is Unique_ptr pertinent for vectors of vectors
这由您决定,但只是在没有其他基础结构知识的情况下快速查看代码,我会说这是一种沉重、可怕的代码味道。我会简单地按原样使用矢量。它更轻、更安全、更简单、更快。
指向 STL 容器的指针通常是代码气味的强烈指标,而指向包含指向 STL 容器指针的 STL 容器的指针具有更强烈的代码气味。这根本不会通过审查,我会敦促简化。
拥有指向 STL 容器的指针实际上不应该存在于代码中,除非有一些 class 通过容器指针封装非常特殊的内存管理,但它们不应该逃避 class。即便如此,您也可以管理内存并使用简单的容器值进行重用。
您应该尝试一下值语义!它有助于局部思考,通常可以使代码更简单。
现在是问题的非意见部分。
让我们删除代码中多余的唯一指针,以便更容易解释:
std::vector<std::vector<std::unique_ptr<CombatObject>>>& Builder_FleetsCombatObjects::BuildFleets(const std::vector<const CombatObject::ConstructionOrder_CombatObject>& orders)
{
std::vector<std::vector<std::unique_ptr<CombatObject>>> fleets{};
Factory_Mechas mFact;
Factory_SpaceShip sFact;
for (auto order : orders)/* No Abstract factory to match schema */
{
if (sFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets.push_back(sFact.CreateSpaceShip(order));
}
else if (mFact.IsMine(order.TypeOfObjectToBuild) != false)
{
fleets.push_back(mFact.CreateMechas(order));
}
}
return fleets;
}
在这段代码中,我们复制并构造了新的向量,并分配了新的唯一指针。
在这里,您的问题将变成:如何确保释放唯一指针的向量向量?
好吧,让我们从看一个整数向量开始:
{
std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
}
// Did we leaked?
这里,我们没有泄露。这是因为 vector 负责分配和释放。它将在推回时释放旧缓冲区,并在向量超出范围时释放。
那么唯一指针呢?
{
std::unique_ptr<int> ptr = std::make_unique<int>(3);
*ptr = 1;
} // Did we leaked?
现在我们泄露了吗?不,那太荒谬了!
现在让我们尝试复制这两种类型:
std::vector<int> vec;
std::unique_ptr<int> ptr = std::make_unique<int>(3);
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
// Copy!
std::vector<int> vec2 = vec;
std::unique_ptr<int> ptr2 = ptr; // Uh oh! Error!
这里如你所见,不能复制唯一指针。复制唯一指针将无法编译。
但是,你可以复制一个向量,那么当你复制一个唯一指针的向量时会发生什么?
std::vector<std::unique_ptr<int>> vec_ptr;
vec_ptr.push_back(std::make_unique<int>(1));
vec_ptr.push_back(std::make_unique<int>(2));
vec_ptr.push_back(std::make_unique<int>(3));
std::vector<std::unique_ptr<int>> vec_ptr2 = vec_ptr; // Error again!
这里还是编译不通过!那是因为要创建缓冲区的副本,您需要复制每个元素。如果无法复制元素,则无法复制向量,因此向量不可复制。
现在由于 vector 完全管理内存,而唯一 ptr 完全管理内存,除非您明确要求唯一指针放弃所有权,否则您不能泄漏任何内存:
std::unique_ptr<int> ptr = std::make_unique<int>(3);
int* raw_owning_pointer = ptr.release();
// Here, I have to delete it myself
现在在您的代码中,无论回推以及唯一指针和向量组合,都没有泄漏!
要真正确保完全没有泄漏,请使用消毒剂或内存调试器(如 valgrind)。