【问题标题】:Reference counted structure exposing a POD interface暴露 POD 接口的引用计数结构
【发布时间】:2014-06-20 09:55:27
【问题描述】:

我目前有一个声明复制构造函数和析构函数的结构,并保持对 pimpl 对象的引用计数。这允许我通过值传递这个结构。我需要重构它,因为我希望它具有 POD 接口,因为它是库的一部分,现在需要从使用旧 C++ 风格的代码中使用它。 因此,我必须同时删除复制构造函数和析构函数。我不知道在我删除它之后如何保持这种良好的“价值传递”,多重所有权机制。共享指针不是一个选项,因为该结构被用作其他类的方法的参数,从库用户的角度来看,这些类也需要被视为 POD。

struct Foo {
  Foo(const Foo&);
  const Foo& operator=(const Foo&);
  ~ Foo();
private:
  void* pimpl;
};

struct MainLibrary {
   void DoSomething(Foo param);
}

现在的用户代码是这样的:

MainLibrary ml;
{
  Foo a;
  ml.doSomething(a);
}

此时,a 变量可以在主库中保存很长时间。为了提高效率,Foo 的内部不能每次都被深度复制,这就是为什么 pimpl 实现保留一个引用计数器,每次复制 Foo 的实例时递增,每次销毁 Foo 的实例时递减。

【问题讨论】:

  • "am old C++ flavor" 不支持调用复制构造函数、析构函数?那怎么可能是C++?您应该重新考虑一下,因为您要求的内容相当于“我无法跟踪这些对象,但我需要在它们全部完成后删除其他一些对象” - 如果没有析构函数,您只能尝试链接垃圾收集器。跨度>
  • 不,问题是我在整个库中使用 C++11,应该可以通过使用不带 C++11 标志编译的代码链接到它……如果我有非 POD 类型然后我在链接时遇到名称修改错误
  • 这是一个非常重要的见解,可以忽略您的问题。在那种情况下,我确信您仍然可以使用一些“胶水”数据和/或函数来使用您当前的设计 - 也许让它们成为外部“C”非成员,以便可以从任何一方调用它们,拥有 C+ +11 代码注册回调,因此 C++11 之前的版本可以找到它需要的函数。还要检查你的编译器文档,看看它们是否提供对名称修改差异的任何控制......
  • 抱歉,我没听懂。你能给我一个你在给定示例代码的情况下谈论的功能的例子吗?非常感谢

标签: c++ reference-counting binary-compatibility


【解决方案1】:

评论太多了......如下所示。客户端包括 foo03.h,它们的使用应该不受影响。您的 C++11 实现是通过“C”层调用的。如果您搜索“将 C++ 代码暴露给 C”或类似内容,您可以找到很多示例......

foo03.h:

extern "C"
{
    void* foo_constructor();
    void* foo_constructor2(void* rhs);
    void foo_assign(void* lhs, void* rhs);
    void foo_destructor(void* p_this);
}

struct Foo {
    Foo() { p_ = foo_constructor(); }
    Foo(const Foo& rhs) { p_ = foo_constructor2(rhs.p_); }
    const Foo& operator=(const Foo& rhs) { foo_assign(p_, rhs.p_); return *this; }
    ~Foo() { foo_destructor(p_); }
  private:
    void* p_;
};

foo11.h:

// up to you whether you call this Foo (relying on mangling differences to avoid conflicts when
// linking with C++03 objects), FooImpl, put it in a namespace ala Impl::Foo etc..
struct FooImpl {
    FooImpl() { ... }
    FooImpl(const FooImpl&) { ... }
    const FooImpl& operator=(const FooImpl& rhs) { ... }
    ~FooImpl() { ... }
};

extern "C"
{
    void* foo_constructor() { return new FooImpl(); }
    void* foo_constructor2(void* rhs) { return new FooImpl(*(FooImpl*)rhs); }
    void foo_assign(void* lhs, void* rhs) { *(FooImpl*)lhs = *(FooImpl*)rhs; }
    void foo_destructor(void* p_this) { delete (FooImpl*)p_this; }
}

【讨论】:

  • @AlexDarsonik 不客气 - 希望一切顺利。
  • 据我所知,普通 C 没有函数重载(并且没有名称修饰来区分它们),所以你的两个 foo_constructors 会发生冲突。
猜你喜欢
  • 1970-01-01
  • 2018-09-30
  • 1970-01-01
  • 2019-02-17
  • 1970-01-01
  • 2021-05-13
  • 2018-05-09
  • 1970-01-01
  • 2019-12-14
相关资源
最近更新 更多