Jon Jon - 25 days ago 7
C++ Question

Keeping a shared_ptr in scope

I have a class that works on a bunch of shared pointers and stores them in various (not mutually exclusive) collections. One of the tasks of the class is to keep these containers up to date when it adds/removes one of these shared pointers.

To facilitate maintaining these collections, I have helper functions that classify a shared pointer, add/remove it from all its associated containers and do any other necessary work. This works well except that, if the remove function is called directly on elements of the containers, the shared pointers are free'ed before the function is finished.

I had solved this by passing the element to the function by value. This gives the function its own copy of the shared pointer and keeps it alive until the function ends. I was happy with this solution (and the need/motivation was commented) but this function keeps getting flagged/changed by code auditing tools (e.g., clang-tidy) as having poor performance and changed to a const reference.

How do I avoid this? The function is a small part of a bigger library and it is understandable that the maintainer is missing the comment. I am not in a position to change the code auditing rules so I would like a simple and efficient way to just avoid this problem? I suspect there may be something smart with C++11 and

std::move
?

An example, if my class was working with
FruitPtr
shared pointers, it may have collections such as,

std::vector<FruitPtr> greenFruit_;
std::vector<FruitPtr> redFruit_;
std::vector<FruitPtr> sweetFruit_;
std::vector<FruitPtr> sourFruit_;


etc.

The problematic function would then look like

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();
}


This works fine, but if it is changed to
removeFruit(const FruitPtr& oldFruit)
then when called directly on elements of a container, e.g.,
removeFruit(greenFruit_[i])
, the pointer
oldFruit
will be destroyed as soon as it is removed from all the containers, before the final operations are performed on the element itself. In my library these operations must be performed at the end of the function as they affect finding the element in the containers.

So, how do I make this function work with a const reference or make it clear to code auditing tools/readers that it cannot?

EDIT
Note:


  • FruitPtr
    is a
    std::shared_pointer<Fruit>

  • The only copies of the pointers may be in the containers that
    removeFruit
    is operating on (assume they are).


Jon Jon
Answer Source

My immediate solution is to have the function make its own copy, e.g.,

removeFruit(const FruitPtr& oldFruit)
{
    FruitPtr fruitToRemove(oldFruit)

    //...

    // Use fruitToRemove everywhere in the function, e.g.,
    fruitToRemove->markSpoiled();
}

but is there something smarter? Like somehow std::move in C++11?