user3408657
user3408657

Reputation: 189

Vector of object pointers from another vector

I have

std::vector<MyObject> obs;

//fill obs...

std::vector<MyObject*> obsA;
std::vector<MyObject*> obsB;

for (MyObject &p: obs){
    if (p.type == "A"){
        obsA.push_back(p);
    }else{
        obsB.push_back(p);
    }
}

where I am trying to create a 2 subsets of some vector of objects. I want the subsets to be pointers, so that any changes made to the object in the obsA or obsB is reflected in the main obs vector. However when I try to run the code I get the following error:

src/main.cpp:55:26: error: no matching function for call to ‘std::vector<MyObject*>::push_back(MyObject&)’

I thought that having & after a variable should give the address to that variable, and since obsA and obsB and vector of pointers, that it should be valid to insert an address of a MyObject into there. What am I doing wrong here?

Upvotes: 0

Views: 88

Answers (2)

Daniel
Daniel

Reputation: 1287

I thought that having & after a variable should give the address to that variable, and since obsA and obsB and vector of pointers, that it should be valid to insert an address of a MyObject into there. What am I doing wrong here?

The most direct answer to your question would be to modify it in the following way. The p is just a reference to some element in obs. &p gives you the address in memory to where p is referencing, which is what the pointer needs.

for (MyObject &p: obs){
    if (p.type == "A"){
        obsA.push_back(&p);
    }else{
        obsB.push_back(&p);
    }
}

The bigger question is why you are doing it this way. This seems very likely to break and do something bad. Anytime you modify the original vector obs (by adding or removing elements), all the pointers in obsA and obsB can be invalidated (i.e., they no longer point to the right place in obs). Changing the size of vector obs can cause a memory reallocation and moving the contents of obs to a new place in memory, which would be a different location from where the elements of obsA and obsB are pointing to. Then any further usage of obsA or obsB would cause undefined behavior, which would lead to abnormal behavior and a likely crash.

There are potential alternatives. For example, replacing the contents of obs with std::shared_ptr<>s can help, but if you remove one element from obs this won't clean it up that element correctly in either obsA or obsB (i.e., either obsA or obsB will still hold that object in memory and it won't be deleted correctly). A combination of std::shared_ptr and std::weak_ptr could work:

std::vector<std::shared_ptr<Obj>> obs;
std::vector<std::weak_ptr<Obj>> obsA, obsB;

for (auto p: obs){
    if (p->type == "A"){
        obsA.push_back(p);
    }else{
        obsB.push_back(p);
    }
}

//... later
for( auto it = obsA.begin(); it != obsA.end(); it++ ) {
    if(auto p = (*it).lock()) { // lock tests if the shared_ptr is still valid
        p->otherMemberVariable = "edit"; //This will also edit the same element in the vector obs
    else {
        //the pointer was removed from obs, remove it here too
        it = obsA.erase(it);
    }
}

But this is getting very complicated, so you may want to rethink your design a bit.

Upvotes: 1

pm100
pm100

Reputation: 50110

You need

 obsA.push_back(&p);

Strongly recommend using shared_ptr rather than raw pointers tho

Upvotes: 0

Related Questions