0

I have searched stackoverflow and found a partial answer to my question already: How to remove elements from a vector based on a condition in another vector? In my case I have two vectors, one containing integers and one containing shared pointers (std::shared_ptr< someType >) and I am not able to figure the pointer arithmetic out the get the code working.

class someAbstractClass
{     
};

class someClass : public someAbstractClass
{
};    

std::vector<int> condition;
std::vector<std::shared_ptr< someAbstractClass >> container;

condition.push_back(0);
condition.push_back(1);
condition.push_back(0);

container.push_back( std::make_shared< someClass > );
container.push_back( std::make_shared< someClass > );
container.push_back( std::make_shared< someClass > );

std::erase( std::remove_if( container.begin(), conatiner.end(),
           [&] ( const std::shared_ptr< someAbstractClass > &s ) 
           { 
               return condition[ &s - &(*container.begin()) ] == 1;
           } ), container.end() );

Is there a way to make this work?

1 Answers1

0

You are comparing shared_ptr objects to each other. You need to instead compare the addresses of those objects. And the lambda needs to take its input argument by reference to ensure it is working with the address of an original object within the vector and not a copy of the object elsewhere in memory.

container.erase(
    std::remove_if(
        container.begin(), container.end(),
        [&](const std::shared_ptr<someType> &s) {
            return condition[ &s - &(*container.begin()) ] == 1;
        }
    ),
    container.end()
);

Live Demo

Compare that to the following snippet in the accepted answer to the question you linked to:

a.erase(remove_if(begin(a), end(a),
    [b&](const myClass& d) { return b[&d - &*begin(a)].alive(); }),
    end(a));

See the similarities?

Subtracting the typed addresses of two valid elements within a container of consecutive memory, like a std::vector, produces an offset between the two elements. And when the lower address is for the 1st element of the container, that offset is effectively the same as the index of the higher address. That is how pointer arithmetic in this example is able to get the index of the lambda argument within condition (provided that condition has at least as many elements as container).

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thank you for your fast and detailed answer. After applying the changes I am still not able to compile the code. "no match for operator== -> operant types std::shared_ptr< someType > and const std::shared_ptr< someType>&" – user1638795 Nov 01 '18 at 15:03
  • Indeed that error message doesn't make much sense. Might help to know what implementation we're talking about. – Lightness Races in Orbit Nov 01 '18 at 15:38
  • @RemyLebeau This really seems implementation specific. The container vector holds objects of an abstract class. – user1638795 Nov 01 '18 at 15:52
  • @user1638795 no, it is not implementation-specific, there is nothing non-standard about what I said or showed. And no, the vector holds `shared_ptr` objects, which are not abstract. Whatever the `shared_ptr` objects hold is irrelevant to this issue – Remy Lebeau Nov 01 '18 at 16:21
  • @RemyLebeau I think my last comment was not clearly formulated. I edited the question to get it closer to my code. – user1638795 Nov 01 '18 at 18:06
  • @user1638795 that doesn't change what I said in my previous comment: "*Whatever the `shared_ptr` objects hold is **irrelevant** to this issue*". You need to operate on the memory addresses of the `shared_ptr` objects themselves, not the addresses of the objects they manage. – Remy Lebeau Nov 01 '18 at 18:14