简体   繁体   中英

How do you push_back a shared_ptr variable to a vector of shared_ptrs in C++?

I'm a C++ beginner with a background in Python, Java, and JS, so I'm still learning the ropes when it comes to pointers.

I have a vector of shared pointers. Inside of a different function, I assign a shared pointer to a variable and add it to the vector. If I try to access the added element after that function exits, a segmentation fault happens:

class Bar
{
private:
    std::vector<std::shared_ptr<Foo>> fooVector;
}

void Bar::addToFoo()
{
    std::shared_ptr<Foo> foo (new Foo(…));
    fooVector.push_back(foo);
}
void Bar::otherMethod()
{
    // this method gets called sometime after addToFoo gets called
    …
    fooVector[anIndex]->baz(); // segfaults
    …
}

But, if push_back a shared pointer and not a variable, it works.

// this works:
fooVector.push_back(std::shared_ptr<Foo>(new Foo(…)));

// this segfaults:
std::shared_ptr<Foo> foo (new Foo(…));
fooVector.push_back(foo);

I believe it happens because the foo variable gets deleted when the addToFoo function exits (correct me if I'm wrong). How do you push_back a shared_ptr variable to a vector of shared_ptrs in C++?


Why Use A Variable

Though pushing shared_ptr s to vectors directly without variables works, I prefer to use variables in order to do this:

std::shared_ptr<Rider> rider;
switch (iProcessorModesParam)
{
    case PEAKS_MODE:
        rider = std::shared_ptr<Rider>(new PeaksRider(…));
        break;
    case RMS_MODE:
        rider = std::shared_ptr<Rider>(new RMSrider(…));
        break;
}
volumeRiders.push_back(rider);

PeaksRider and RMSrider are subclasses of Rider. I want to store all subtypes of Rider in the same vector of Riders. I learned that adding subtypes of Rider to a vector of Riders doesn't work and pointers are needed in order to achieve this kind of polymorphism:

std::vector<Rider> // doesn’t work with subtypes

std::vector<*Rider>
std::vector<std::shared_ptr<Rider>>

Having the std::shared_ptr<Rider> rider; variable avoids repeating the .push_back(…) code for each type of Rider.

Instead of assigning shared pointer, user reset method.

rider.reset(new PeaksRider(…));

other that this, your code snippets seems to okay to me.

segfault may have caused because of the index variable ( which may be out of range). i suggest you to use .at(index) for accessing pointer from vector and wrap that part of code in a try..catch block and see what is the real error.

And regarding...

I believe it happens because the foo variable gets deleted when the addToFoo function exits (correct me if I'm wrong).

This is not true, share_ptrs use a local counter for #of references. as soon as you pushed the pointer to vector the counter gets incremented to 2 and event after control exits the function the counter is decremented to 1. so, your object is not destroyed yet.

There is no problem on creating a shared pointer instance, storing it in a variable, and doing a push_back to a vector after that. Your code should be fine as long as the index that you use when calling "otherMethod" is valid. However, I have a couple of suggestions for your code:

  • When you create a shared_ptr, it is highly recommended to do it through "std::make_shared" to ensure the safety and correctness of your code in all situations. In this other post you will find a great explanation: Difference in make_shared and normal shared_ptr in C++
  • When accessing positions of a vector using a variable that may contain values that would cause an out-of-bounds access (which usually leads to segmentation faults) it is a good practice to place asserts before using the vector, so you will detect these undesired situations.

I just wrote a small snippet that you can test to illustrate what I just mentioned:

#include <iostream>
#include <vector>
#include <memory>
#include <cassert>

class Foo
{
public:
    int data = 0;
};

class Bar
{
public:
    void addNewFoo(int d)
    {
        std::shared_ptr<Foo> foo(new Foo());
        foo->data = d;
        fooVector.push_back(foo);
    }

    void addNewFooImproved(int d)
    {
        auto foo = std::make_shared<Foo>();
        foo->data = d;
        fooVector.push_back(foo);
    }

    void printFoo(int idx)
    {
        assert(idx < fooVector.size());
        std::cout << fooVector[idx]->data << std::endl;
    }

private:
    std::vector<std::shared_ptr<Foo>> fooVector;
};

int main()
{
    Bar b;
    b.addNewFoo(10);
    b.addNewFoo(12);
    b.addNewFooImproved(22);
    b.printFoo(1);
    b.printFoo(2);
    b.printFoo(0);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM