2010-03-25 5 views
3

Я просматривал альтернативу использованию так много 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

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

E.g.

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

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

+0

Я бы добавил, что в этом случае auto_ptr имеет лучшую комбинацию гибкости и простоты, поскольку он больше не нуждается в подсчете ссылок. –

+1

Не слишком ли хорошо понятен auto_ptr, чтобы использовать его правильно, из-за «несколько странной» семантики копирования? –

3

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

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

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

+0

Просто имейте в виду, что это делает «FooManager» невозможным. –

+0

Да, это работа для 'boost: scoped_ptr'. Задавайте его каждый раз, используя 'void reset (T * p = 0); // никогда не бросает'. –

+0

@BillyONeal: Это верно: он подавляет неявный конструктор и оператор присваивания, но это не мешает вам реализовать пользовательский конструктор копирования и оператор присваивания. Если вам не нужна совместная собственность, это, вероятно, не будет большой проблемой. –

2

Используйте идиому 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; 
} 

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

+0

Является ли идиома pimpl критической для решения? Каково соответствующее преимущество над 'scoped_ptr m_foo' (или даже просто Foo * m_foo) в заголовке и' Foo & getFoo() {if (! M_foo) m_foo.reset (new Foo); return * m_foo} 'в файле cpp? – Kyle

+0

Нет, это не так. Идиома pimpl была нацелена на аспект «уменьшить заголовок», вам не нужно далеко ходить. –