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

发布于 2024-08-26 15:24:51 字数 705 浏览 6 评论 0原文

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

您真的需要共享所有权吗? 如果你停下来思考一些 分钟,我相信你能指出其中一个 对象的所有者,以及一些 它的用户,只会使用 它在所有者的一生中。所以 只需将其设为本地/成员对象 的所有者,并传递引用 那些需要使用它的人。

我很乐意这样做,但问题是拥有对象的定义现在需要首先完全定义拥有的对象。例如,假设我在 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 同时初始化。我该如何解决这些问题?

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 to 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

行雁书 2024-09-02 15:24:51

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

例如

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

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

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.)

旧时模样 2024-09-02 15:24:51

如果您不需要 shared_ptr 的共享所有权语义,请考虑使用不同的智能指针容器。

根据您给出的示例(一个拥有所有权且没有所有权转让的对象),boost::scoped_ptr 将是一个不错的选择。

如果您不想使用 Boost,scoped_ptr 非常容易实现——Boost 文档对其进行了详细描述,并且其实现(在 boost/shared_ptr.hpp 中)也很简单。

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.

回眸一笑 2024-09-02 15:24:51

使用 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 的部分原因)。

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文