在作用域中保持shared_ptr
Keeping a shared_ptr in scope
我有一个类,它在一堆共享指针上工作,并将它们存储在各种(而不是互斥)集合中。类的任务之一是在添加/删除这些共享指针时保持这些容器是最新的。
为了方便维护这些集合,我有一些辅助函数来对共享指针进行分类,将其从所有相关的容器中添加/删除,并执行任何其他必要的工作。除了,如果在容器的元素上直接调用remove函数,则在函数完成之前释放共享指针。
我已经通过按值传递元素给函数解决了这个问题。这为函数提供了自己的共享指针副本,并使其保持活动状态,直到函数结束。我对这个解决方案很满意(并且需要/动机被注释了),但是这个函数不断被代码审计工具(例如clang-tidy)标记/更改为性能差并更改为const引用。
如何避免这种情况?这个函数只是一个更大的库的一小部分,维护人员缺少注释是可以理解的。我不能改变代码审计规则,所以我想一个简单而有效的方法来避免这个问题?我怀疑c++ 11和std::move
可能有一些聪明的地方?
FruitPtr
共享指针,它可能有这样的集合,
std::vector<FruitPtr> greenFruit_;
std::vector<FruitPtr> redFruit_;
std::vector<FruitPtr> sweetFruit_;
std::vector<FruitPtr> sourFruit_;
等。
有问题的函数看起来像
removeFruit(FruitPtr oldFruit)
{
// Remove the element from any containers it belongs to:
if (/*Some container condition*/)
{
//Find and remove from container
}
// etc., for all containers
// Do some final operations on the element that must occur after it is removed from the containers,
oldFruit->markSpoiled();
}
这工作得很好,但是如果它被更改为removeFruit(const FruitPtr& oldFruit)
,那么当在容器的元素上直接调用时,例如,removeFruit(greenFruit_[i])
,指针oldFruit
将在从所有容器中移除后立即被销毁,在对元素本身执行最终操作之前。在我的标准库中,这些操作必须在函数末尾执行,因为它们会影响在容器中查找元素。
那么,我如何使这个函数与const引用一起工作,或者让代码审计工具/读者清楚地知道它不能?
编辑注意:
-
FruitPtr
是std::shared_pointer<Fruit>
- 指针的唯一副本可能在
removeFruit
操作的容器中(假设它们是)。
我的直接解决方案是让函数自己创建副本,例如
removeFruit(const FruitPtr& oldFruit)
{
FruitPtr fruitToRemove(oldFruit)
//...
// Use fruitToRemove everywhere in the function, e.g.,
fruitToRemove->markSpoiled();
}
但是有没有更聪明的方法?就像c++ 11中的std::move
一样?
智能指针并不是一个不用担心生命周期或指针的解决方案,但是它们可以使简单的情况变得不那么复杂。
让我假设FruitPtr
是std::shared_ptr<Fruit>
的类型定义/使用。
在这种情况下,我们可以假设这个指针的唯一副本在你的存储中,否则,你就不会崩溃。
简单的解决方案是这样写:
void removeFruit(FruitPtr oldFruit);
通过这样做,您将在堆栈上拥有shared_ptr的副本,并且随后将清理实际实现。
假设您不想要shared_ptr的副本,可以这样写:
void removeFruit(const FruitPtr &oldFruit) {
FruitPtr tempStorage;
switch (oldFruit.getType()){
case Fruit::Type::Green: {
auto itFind = std::find(begin(greenFruit_), end(greenFruit_), oldFruit);
assert(itFind != end(greenFruit_));
tempStorage = std::move(*itFind);
greenFruit_.erase(itFind);
break;
}
//...
}
// Some code
tempStorage->markSpoiled();
} // Destroys instance if tempStorage.unique() == true.
最后,人们可能会想知道为什么您甚至使用markSpoiled
函数。这很可能是因为其他代码共享了所有权,而实际上它不应该拥有所有权。在这种情况下,std::weak_ptr
是你所需要的。
任何代码仍然有一些对Fruit的引用,将存储std::weak_ptr<Fruit>
,并且必须调用lock()
来获得shared_ptr。如果这个shared_ptr的最后一个实例被删除,这个指针将是nullptr
。
这个问题存在于两个层面:一个是编写实现所需所有权/生命周期语义的代码的技术层面,另一个是您和库维护人员之间的沟通和管理问题——它似乎使解决第一个问题变得相当困难。
关于解决第二个问题,我没有太多建议,只能和维护者交谈,耐心而有策略地解释他们对你代码的修改会改变它的语义,需要你们仔细考虑并达成一致。虽然他们可能只是盲目地应用审计工具生成的建议,但他们很可能有令人信服的理由坚持这些更改。当然,我说起来容易,你做起来难。解决技术问题的一种可能方法是让removeFruit()
返回输入FruitPtr
的副本——这将使Fruit
对象保持活动状态,直到调用者决定如何处理它。
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- dopen():不以 root 身份运行时"failed to map segment from shared object"
- C++中的指针否定 (!ptr == NULL)
- 从const ptr*转换为ptr*时出现问题
- 无法使用 libtool 将 -shared 参数传递给 g++
- boost::shared_ptr和std::shared-ptr的同居
- 我可以用std::shared_ptr而不是boost::shared-ptr构建boost库吗
- shared-ptr-C++shared_ptr与unique_ptr用于资源管理