用最少的代码实现 pImpl

发布于 2024-08-23 03:05:38 字数 579 浏览 10 评论 0原文

可以使用哪些技巧来最小化实现 pImpl 类的工作量?

标题:

class Foo {
    struct Impl;
    boost::scoped_ptr<Impl> self;
public:
    Foo(int arg);
    ~Foo();
    // Public member functions go here
};

实现:

struct Foo::Impl {
    Impl(int arg): something(arg) {}
    // All data members and private functions go here
};

Foo::Foo(int arg): self(new Impl(arg)) {}
Foo::~Foo() {}

// Foo's public functions go here (and they refer to data as self->something)

您将如何改进这一点,使用 Boost、可能的继承、CRTP 或其他技巧来避免尽可能多的样板代码?运行时性能不是问题。

What kind of tricks can be used to minimize the workload of implementing pImpl classes?

Header:

class Foo {
    struct Impl;
    boost::scoped_ptr<Impl> self;
public:
    Foo(int arg);
    ~Foo();
    // Public member functions go here
};

Implementation:

struct Foo::Impl {
    Impl(int arg): something(arg) {}
    // All data members and private functions go here
};

Foo::Foo(int arg): self(new Impl(arg)) {}
Foo::~Foo() {}

// Foo's public functions go here (and they refer to data as self->something)

How would you improve this, using Boost, possibly inheritance, CRTP or other tricks to avoiding as much boilerplate code as is possible? The runtime performance is not an issue.

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

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

发布评论

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

评论(2

夜血缘 2024-08-30 03:05:38

来自 Loki 的 pimpl 实现 可能是一个很好的答案。另请参阅有关此内容的 DDJ 文章

Implementation of pimpl from Loki may be a good answer. See also a DDJ Article on this.

烟凡古楼 2024-08-30 03:05:38

这是可能的,但天真的实现并不是您想要的。

问题是模板通常是内联的,天真的实现是:

template <class Object>
class Pimpl
{
public:
  explicit Pimpl(Object* obj): mObject(obj) {}
  ~Pimpl() { delete mObject; }

  // either deep copy or no copy
private:
  Object* mObject;
};

现在的问题是你不希望 Object 在你的头文件中被识别(不是为了二进制兼容性,而是为了依赖管理)。如果 Object 未知,则无法直接实现 DestructorCopy ConstructorAssignment Operator。 !

然而问题远非无法解决 Boost 确实已经解决了 shared_ptr 的问题。

这个想法是在构造函数中传递第二个项目,它将负责释放第一个项目的内存,并且将提供一个很好的默认实现。

当然,这适用于间接。

namespace detail {
  template <class Object>
  struct Deleter { virtual void do(Object*) = 0; };
}

template <class Object>
class Pimpl
{
public:
  typedef detail::Deleter<Object> deleter_type;
  typedef boost::shared_ptr<deleter_type> deleter_pointer;

  Pimpl(std::auto_ptr<Object> obj, deleter_pointer del);
  ~Pimpl();
  Pimpl(const Pimpl&);
  Pimpl& operator(const Pimpl&);

private:
  Object* mObject;
  deleter_pointer mDeleter;
};

这是 C++ 中的经典习惯用法,添加了另一个间接级别:)

It is possible, but a naive implementation is not what you want.

The problem is that templates are generally inlined, the naive implementation would be:

template <class Object>
class Pimpl
{
public:
  explicit Pimpl(Object* obj): mObject(obj) {}
  ~Pimpl() { delete mObject; }

  // either deep copy or no copy
private:
  Object* mObject;
};

Now the problem is that you don't want Object to be known in your header file in general (not for binary compatibility, but for dependency management). And if Object is not known, then you cannot implement the Destructor, Copy Constructor and Assignment Operator directly...

The problem is far from being unsolvable however! Boost indeed has solve it for the shared_ptr.

The idea is to pass a second item in the constructor, that will take care of releasing the memory of the first, and that will be provided with a nice default implementation.

This works with an indirection, of course.

namespace detail {
  template <class Object>
  struct Deleter { virtual void do(Object*) = 0; };
}

template <class Object>
class Pimpl
{
public:
  typedef detail::Deleter<Object> deleter_type;
  typedef boost::shared_ptr<deleter_type> deleter_pointer;

  Pimpl(std::auto_ptr<Object> obj, deleter_pointer del);
  ~Pimpl();
  Pimpl(const Pimpl&);
  Pimpl& operator(const Pimpl&);

private:
  Object* mObject;
  deleter_pointer mDeleter;
};

It's a classic idiom in C++, add yet another level of indirection :)

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