How to use references, avoid header bloat, and delay initialization?
I was browsing for an alternative to using so many shared_ptrs, and found an excellent reply in a comment section:
Do you really need shared ownership? If you stop and think for a few minutes, I'm sure you can pinpoint one owner of the object, and a number of users of it, that will only ever use it during the owner's lifetime. So simply make it a local/member object of the owners, and pass references to those who need to use it.
I would love t开发者_运维问答o do this, but the problem becomes that the definition of the owning object now needs the owned object to be fully defined first. For example, say I have the following in FooManager.h:
class Foo;
class FooManager
{
shared_ptr<Foo> foo;
shared_ptr<Foo> getFoo() { return foo; }
};
Now, taking the advice above, FooManager.h becomes:
#include "Foo.h"
class FooManager
{
Foo foo;
Foo& getFoo() { return foo; }
};
I have two issues with this. First, FooManager.h is no longer lightweight. Every cpp file that includes it now needs to compile Foo.h as well. Second, I no longer get to choose when foo is initialized. It must be initialized simultaneously with FooManager. How do I get around these issues?
You can use a shared_ptr
( or any smart pointer, or even a dumb pointer) but not have shared ownership.
E.g.
class Foo;
class FooManager
{
private:
shared_ptr<Foo> foo;
public:
Foo& getFoo() { return *foo; }
};
(This is just a sketch - you still need a setFoo(), and perhaps getFoo() should return a Foo *. But the point is that you're back to being lightweight, and you can control when foo is created.)
If you don't need the shared ownership semantics of shared_ptr
, consider using a different smart pointer container.
With the example you give (one object having ownership and no transferral of ownership), boost::scoped_ptr
would be a good choice.
If you don't want to use Boost, scoped_ptr
is very easy to implement--it's well described in the Boost documentation and its implementation (in boost/shared_ptr.hpp) is straightforward.
Use the pimpl idiom, and stop inlining so much.
FooManager.h:
class Foo;
class FooManager
{
struct Impl;
Impl *m_impl;
public:
Foo& getFoo();
FooManager();
~FooManager();
};
FooManager.cpp
#include "Foo.h"
#include "FooManager.h"
struct FooManager::Impl
{
Foo* m_foo;
int m_someothermember;
FooManager::Impl() : m_foo(NULL), m_someothermember(0) {}
};
FooManager::FooManager() : m_impl(new FooManager::Impl())
{}
Foo& FooManager::getFoo()
{
// Lazy initialization
if( !m_impl->m_foo ) {
m_impl->m_foo = new Foo;
}
return *m_impl->m_foo;
}
FooManager::~FooManager()
{
delete m_impl->m_foo;
delete m_impl;
}
Since you're already using boost I would recommend you use scoped_ptr
to implement this in your real code instead of manually managing the memory as I've done in this example. The important thing to keep in mind is forward declaring works just as well for references as it does for pointers (which is part of the reason it worked for shared_ptr
).
精彩评论