Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to delete a std::unique_ptr from a vector with a raw pointer?

So I have a vector like so:

std::vector<std::unique_ptr<SomeClass>> myVector;

Then I have another vector which contains raw pointers of SomeClass:

std::vector<SomeClass*> myOtherVector;

If there is an element inside myOtherVector it will also be inside myVector, so I want to go through each element in myOtherVector and remove the same element from myVector. Then clear out the vector. This is what I came up with:

for(size_t i = 0; i < myOtherVector.size(); i++)
{
    myVector.erase(std::remove(myVector.begin(), myVector.end(), myOtherVector[i]), myVector.end());
}
myOtherVector.clear();

This produces a compile time error because myVector holds unique pointers but I'm giving the remove() function a raw pointer. This is where I need help because I don't know what the proper way to solve this problem would be. I changed the line to:

myVector.erase(std::remove(myVector.begin(), myVector.end(), std::unique_ptr<SomeClass>(myOtherVector[i])), myVector.end());

Frist of all this is incorrect because now I have two std::unique_ptrs referencing the same object. The element inside myVector contains a reference and the construction of the unique pointer in the above line is another reference. And I don't even know if constructing a new pointer to get the same type is conceptually the correct way to go about doing this. So then I changed the unique pointers to shared pointers:

std::vector<std::shared_ptr<SomeClass>> myVector;
std::vector<SomeClass*> myOtherVector;

for(size_t i = 0; i < myOtherVector.size(); i++)
{
    myVector.erase(std::remove(myVector.begin(), myVector.end(), std::shared_ptr<SomeClass>(myOtherVector[i])), myVector.end());
}
myOtherVector.clear();

When I ran the application the myVector.erase() line resulted in a runtime error which said "ApplicationName.exe has triggered a breakpoint." upon clicking continue I got a debug assertion failure.

So obviously I'm doing something wrong, but I don't know what. What is the correct way to erase a smart pointer from a vector with a raw pointer?

like image 697
ProgrammerGuy123 Avatar asked Feb 28 '13 01:02

ProgrammerGuy123


People also ask

Can you delete a unique_ptr?

An explicit delete for a unique_ptr would be reset() . But do remember that unique_ptr are there so that you don't have to manage directly the memory they hold. That is, you should know that a unique_ptr will safely delete its underlying raw pointer once it goes out of scope.

How do you remove an element from a vector in C++?

vector::erase() erase() function is used to remove elements from a container from the specified position or range.


2 Answers

This is how I would do it. Performance could be improved, but as long as it won't prove to be a bottleneck for your application, I would not bother with that. The algorithm is simple and clear.

It uses remove_if to selectively remove from the first container (myVector) all the elements pointing to objects that are pointed to by elements of the second container (myOtherVector); then, it clears the second container. The predicate is implemented through a lambda function:

#include <vector>
#include <memory>
#include <algorithm>

struct SomeClass { /* ... */ };

int main()
{
    std::vector<std::unique_ptr<SomeClass>> myVector;
    std::vector<SomeClass*> myOtherVector;

    myVector.erase(
        std::remove_if( // Selectively remove elements in the second vector...
            myVector.begin(),
            myVector.end(),
            [&] (std::unique_ptr<SomeClass> const& p)
            {   // This predicate checks whether the element is contained
                // in the second vector of pointers to be removed...
                return std::find(
                    myOtherVector.cbegin(), 
                    myOtherVector.cend(), 
                    p.get()
                    ) != myOtherVector.end();
            }),
        myVector.end()
        );

    myOtherVector.clear();
}
like image 188
Andy Prowl Avatar answered Oct 17 '22 08:10

Andy Prowl


std::unique_ptr has a member function, get, that returns the owned pointer.

Consider the following:

std::sort(myOtherVector.begin(), myOtherVector.end());

myVector.erase(std::remove_if(myVector.begin(), myVector.end(),
[&](std::unique_ptr<SomeClass> const& p) -> bool
{
    return std::binary_search(myOtherVector.begin(), myOtherVector.end(),
                              p.get());
}));

myOtherVector.clear();    
like image 41
James McNellis Avatar answered Oct 17 '22 07:10

James McNellis