views:

83

answers:

3

Hello folks,

I need to store references to instances of derived classes in C++. I considered using a vector of shared_ptrs to the base class (for it needs to hold different types of derived classes), however, it's important that the container holds the original pointers, which is not the case with vectors (or other stl containers), if I'm not mistaken. Is there a way to do this in native C++, or do I have to use special containers like Boost's ptr_vector?

EDIT: This is my test code:

class Foo
{
public:
    Foo() {}
    virtual ~Foo() {}
    virtual void set_x(int i) = 0;
};

class Bar : public Foo
{
public:
    Bar() {}

    void set_x(int i)
    {
        this->x = i;
    }

    int x;
};

int main()
{
    Bar bar;

    // ptr
    std::cout << &bar << "\n";

    std::vector<Foo*> foos;
    foos.push_back(&bar);

    // different ptr value
    std::cout << &foos[0] << "\n";

    foos[0]->set_x(1);

    // however, changes are made
    std::cout << bar.x;

    return 0;
}

Thanks in advance,

jena

A: 

If you use shared_ptr as your container member, the pointer in each member will retain access to the original object instance. You can get a copy of a shared_ptr at any point after container housekeeping, but the original object will still be its target.

For a simpler solution you might use boost::ptr_vector, provided none of your pointers occur twice in the container - that scenario would introduce tricky resource management complexity and point you back to shared_ptr.

Steve Townsend
Do shared_ptr make sense with types that are not allocated on the heap?
jena
Nope. In that case when the variable goes out of scope, your `shared_ptr` will point to junk on the stack, maybe even inaccessible memory after stackframe unwind.
Steve Townsend
+1  A: 

You can create a std::vector<foo*>, which will hold any pointers to foo that you hand to it. It won't make any attempt to delete those pointers on destruction, which may or may not be what you want, but it will hold exactly the values you pass in.

You can also create an std::vector< shared_ptr<foo> >, which will hold pointers that will be released once there are no dangling copies of the shared_ptr floating around. Those will also hold the "original" foo* you passed in; you can get it again by using the shared_ptr::get() method.

The only time you wouldn't see exactly the same pointer as your derived object is if you're using multiple inheritance of classes, and your base classes include data. Because a foo* would end up, in that case, pointing to the "foo" part of the data, which wouldn't necessarily be at the "root" of the object.

SomeCallMeTim
I do not use multiple inheritance, but the base class contains data. Might this be the reason for elements in the vector to have different pointers from the originals?
jena
Didn't see your example the first time; the other answer already hit the meat of your problem, which was that you were getting the address of the VECTOR data and not the pointer itself. Sleep is an important part of development. :)
SomeCallMeTim
+1  A: 

In your example above, what you are printing out is the address of the pointer not the value of the pointer.

Instead of:

// different ptr value
std::cout << &foos[0] << "\n";

Do

// different ptr value
std::cout << foos[0] << "\n";

Aside from that your vector<Foo*> will work just fine.

JoshD
This is depressing... You are right, of course. Thanks for pointing that out, I should really consider some sleep. Thanks to all for your help - I apologize for this voidness.
jena
I'm glad I could help. If it was a good solution, could you please mark it as the accepted answer?
JoshD