C++ 如何使用引用、避免标头膨胀和延迟初始化?

C++ 如何使用引用、避免标头膨胀和延迟初始化?,c++,initialization,reference,header-files,smart-pointers,C++,Initialization,Reference,Header Files,Smart Pointers,我正在浏览一个替代使用这么多共享的PTR的方法,并在评论部分找到了一个很好的回复: 你真的需要共享所有权吗? 如果你停下来想一想 分钟,我相信你能找到一个 对象的所有者,以及 它的用户,将永远只使用 它将在所有者的有生之年进行。所以 只需将其设置为本地/成员对象 并将引用传递给 那些需要使用它的人 我很想这样做,但问题是拥有对象的定义现在需要首先完全定义拥有对象。例如,假设我在FooManager.h中有以下内容: class Foo; class FooManager { share

我正在浏览一个替代使用这么多共享的PTR的方法,并在评论部分找到了一个很好的回复:

你真的需要共享所有权吗? 如果你停下来想一想 分钟,我相信你能找到一个 对象的所有者,以及 它的用户,将永远只使用 它将在所有者的有生之年进行。所以 只需将其设置为本地/成员对象 并将引用传递给 那些需要使用它的人

我很想这样做,但问题是拥有对象的定义现在需要首先完全定义拥有对象。例如,假设我在FooManager.h中有以下内容:

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

class FooManager
{
   struct Impl;
   Impl *m_impl;
public:
   Foo& getFoo();

   FooManager();
   ~FooManager();
};

我有两个问题。首先,FooManager.h不再是轻量级的。包括它的每个cpp文件现在也需要编译Foo.h。第二,我不再需要选择何时初始化foo。它必须与FooManager同时初始化。如何解决这些问题?

< P>如果您不需要共享代码所有权的代码> SydDypTr>/Cult>,请考虑使用不同的智能指针容器。 根据您给出的示例(一个对象拥有所有权,但没有所有权转让),
boost::scoped_ptr
将是一个不错的选择


如果您不想使用Boost,
作用域ptr
非常容易实现——Boost文档中对其进行了详细描述,它的实现(在Boost/shared_ptr.hpp中)非常简单。

您可以使用
共享_ptr
(或任何智能指针,甚至哑指针),但不具有共享所有权

例如

Foo类;
班级经理
{
私人:
共享_ptr foo;
公众:
Foo&getFoo(){return*Foo;}
};

(这只是一个草图-您仍然需要一个setFoo(),也许getFoo()应该返回一个Foo*。但问题是,您又回到了轻量级,您可以控制Foo的创建时间。)

使用pimpl习惯用法,停止过多内联

FooManager.h:

class Foo; 
class FooManager
{
    shared_ptr<Foo> foo;
    shared_ptr<Foo> getFoo() { return foo; }
};
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,我建议您在实际代码中使用
范围化的\u ptr
来实现这一点,而不是像我在本例中所做的那样手动管理内存。需要记住的重要一点是,前向声明对于引用和指针的效果一样好(这也是它用于
共享\u ptr
的部分原因)。

是的,对于
boost:scoped \u ptr
的作业。无论何时通过无效重置(T*p=0)设置它;//从不抛出@BillyONeal:没错:它会抑制隐式复制构造函数和赋值运算符,但不会阻止您实现用户定义的复制构造函数和赋值运算符。但是,如果您不需要共享所有权,这可能不会是一个大问题。我要补充的是,在这种情况下,auto_ptr具有灵活性和简单性的最佳组合,因为他不再需要引用计数功能。auto_ptr不是因为“有些奇怪”而很难正确使用吗复制语义?pimpl习惯用法对解决方案至关重要吗?与头文件中的
scoped_ptr m_foo
(甚至只是foo*m_foo)和
foo&getFoo(){if(!m_foo)m_foo.reset(new foo);在cpp文件中返回*m_foo}
相比,相关的优势是什么?不是。pimpl习惯用法是针对“reduceheaderbloat”方面的,您不需要走这么远。