bombax
bombax

Reputation: 1219

C++: Exposing pointers to class with managed memory

I have the following setup:

class Foo {
public:
    Foo() {}

    vector<BigObject*> mPointers;
};
class Bar {
public:
    Foo *exposeSomeFoo() { return &mFoos[42]; }
private:
    vector<Foo> mFoos;
    vector<BigObject> mMemoryManaged;
};

I'm basically trying to make sure that at no point in my code will someone accidentally use a Foo for which the Bar it was exposed from has gone out of scope.

But this is obviously problematic. If I expose pointers to Foo like above, they become invalid once Bar goes out of scope. If I instead use Foo exposeSomeFoo(), the mPointers will become invalid once Bar goes out of scope, too - and returning copies seems like a bad idea if mPointers has a lot of elements!

I've tried solving this by making a private copy constructor:

class Foo {
public:
    Foo() {}

    vector<BigObject*> mPointers;
private:
    Foo(const Foo&);
};

But then I get errors when I try to insert a Foo into mFoos from within Bar.

There must be a paradigm that allows full memory safety while still allowing me to expose functionality like this. How can I expose, to code elsewhere, a composite object from Bar whose memory is managed specifically by Bar or at least in the compilation unit itself?

Upvotes: 0

Views: 71

Answers (2)

bombax
bombax

Reputation: 1219

Actually, I ended up doing something like this:

class Foo {
public:
    Foo(shared_ptr<vector<BigObject> > bigObjects) : mBigObjects(bigObjects) {

    }
private:
    vector<BigObject*> mPointers;
    shared_ptr<vector<BigObject> > mBigObjects;
};

class Bar {
public:
    Bar() {
        mBigObjects = shared_ptr<vector<BigObject> >(new vector<BigObject>);
        for (int i = 0; i < 100; i++)
            mBigObjects->push_back(BigObject());
        for (int i = 0; i < 100; i++)
            mFoos.push_back(Foo(mBigObjects));
    }
    Foo exposeSomeFoo() { return mFoos[42]; }
private:
    shared_ptr<vector<BigObject> > mBigObjects;
    vector<Foo> mFoos;
};

I think this is the behavior I want: only when all instances of both Foo and Bar are destroyed, is the vector with BigObjects actually destroyed. Can someone double-check that this is safe and good practice? Thanks!

Upvotes: 0

Barry
Barry

Reputation: 303087

If you want to make sure that all of your objects can share resources, such that the resource is alive as long as all of the objects are, just use std::shared_ptr everywhere:

class Foo {
public:
    Foo() {}

    vector<shared_ptr<BigObject>> mPointers;
};

class Bar {
public:
    shared_ptr<Foo> exposeSomeFoo() { return mFoos[42]; }
private:
    vector<shared_ptr<Foo>> mFoos;
    vector<shared_ptr<BigObject>> mMemoryManaged;
};

That way, a caller can hold onto bar.exposeSomeFoo() without worry - the caller now shares ownsership of it, sot his will be perfectly safe.

Upvotes: 1

Related Questions