Как использовать ссылки, избежать раздувания заголовка и отложить инициализацию? - PullRequest
3 голосов
/ 25 марта 2010

Я искал альтернативу использованию такого количества shared_ptrs и нашел отличный ответ в разделе комментариев:

Вам действительно нужно совместное владение? Если вы остановитесь и подумаете несколько минут, я уверен, что вы можете определить одно владелец объекта, а также ряд пользователи, которые будут только когда-либо использовать это при жизни владельца. Так просто сделайте его локальным / членом объекта владельцев и передать ссылки на те, кому нужно его использовать.

Я бы с удовольствием это сделал, но проблема заключается в том, что для определения объекта-владельца теперь необходимо сначала полностью определить объект-владелец. Например, скажем, у меня есть следующее в FooManager.h:

class Foo; 
class FooManager
{
    shared_ptr<Foo> foo;
    shared_ptr<Foo> getFoo() { return foo; }
};

Теперь, следуя приведенному выше совету, FooManager.h становится:

#include "Foo.h"
class FooManager
{
    Foo foo;
    Foo& getFoo() { return foo; }
};

У меня есть две проблемы с этим. Во-первых, FooManager.h больше не легкий. Каждый файл cpp, который включает его, теперь должен также компилировать Foo.h. Во-вторых, я больше не могу выбирать, когда инициализируется foo. должен быть инициализирован одновременно с FooManager. Как мне обойти эти проблемы?

Ответы [ 3 ]

3 голосов
/ 25 марта 2010

Вы можете использовать shared_ptr (или любой умный указатель, или даже тупой указатель), но не иметь общего владения.

Е.Г.

class Foo; 
class FooManager
{
  private:
    shared_ptr<Foo> foo;
  public:
    Foo& getFoo() { return *foo; }
};

(Это всего лишь эскиз - вам все еще нужен setFoo (), и, возможно, getFoo () должен вернуть Foo *. Но дело в том, что вы вернулись к тому, чтобы быть легковесным, и вы можете контролировать, когда создается foo .)

3 голосов
/ 25 марта 2010

Если вам не нужна семантика общего владения shared_ptr, рассмотрите возможность использования другого контейнера интеллектуального указателя.

В приведенном вами примере (один объект, имеющий право собственности и не передающий право собственности), boost::scoped_ptr будет хорошим выбором.

Если вы не хотите использовать Boost, scoped_ptr очень легко реализовать - это хорошо описано в документации Boost, и его реализация (в boost / shared_ptr.hpp) проста.

2 голосов
/ 25 марта 2010

Используйте идиому pimpl, и перестаньте так много вставлять.

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;
 }

Поскольку вы уже используете boost, я бы порекомендовал вам использовать scoped_ptr для реализации этого в вашем реальном коде, вместо того, чтобы вручную управлять памятью, как я делал в этом примере. Важно помнить о том, что объявление о предстоящем объявлении работ так же хорошо, как и об указателях (это одна из причин, по которой он работал для shared_ptr).

...