【问题标题】:C opaque pointer gotchasC 不透明指针陷阱
【发布时间】:2011-03-14 21:14:22
【问题描述】:

我正在使用一个遗留的 C 库接口(到 C++),它将不透明指针公开为

typedef void * OpaqueObject

在图书馆里:

OpaqueObject CreateObject()
{
   return new OurCppLibrary::Object();
}

这当然不会为这个库的客户提供任何类型安全。将 typedef 从 void 指针更改为结构指针是否应该完全相同,但提供少量类型安全?

typedef struct OpaqueObjectInternal_ *OpaqueObject 
// OpaqueObjectInternal_ is NEVER defined anywhere in client or library code

现在我明确指向一个结构,即使我真的没有指向一个结构,是否还有任何对齐问题或其他需要担心的问题?

【问题讨论】:

  • C 中没有名为new 的运算符!!
  • @Mahesh:我认为 OP 正在用 C++ 包装一个 C 库; new 发生在 C++ 中(从 OurCppLibrary 限定符推断)
  • void * 作为一个不透明的对象非常有意义 - 你的事情的结束不会弄乱对象,他们知道如何处理它。如果有的话,将其设为 void * 会更安全,只要您按照描述将其与他们的 API 一起使用即可。
  • @James:我不明白,删除类型信息如何使它更安全?考虑这个例子:void some_api_func(void*); int* i = ...; some_api_func(i); // oops!。类型安全不会发生这种情况。
  • @James:我真的希望编译器能够捕获尽可能多的错误。如果给你一个 ObjectInternal_ *,你打算用它做什么?我认为传递错误对象的可能性要远大于使用没有内部结构或使用它的方法的类型。

标签: c++ c typedef opaque-pointers


【解决方案1】:

没有陷阱;正是因为类型安全,这种形式才是首选。

不,对齐不是问题。指针本身有一个已知的对齐方式,它所指向的对象的对齐方式只与库实现有关,与用户无关。

【讨论】:

    【解决方案2】:

    实际上,C++ 类也是 C 结构。所以你可以简单地这样做:

    struct Object;
    struct Object* Object_Create(void);
    

    而且,库中的 C 包装器:

    struct Object* Object_Create(void)
    {
        return new Object;
    }
    

    方法调用可能如下所示:

    uint32_t Object_DoSomething( struct Object* me, char * text )
    {
        return me->DoSomething( text );
    }
    

    我已经尝试过了,我没有发现任何缺点。

    【讨论】:

      【解决方案3】:

      对于您建议的课程,首先要考虑的是您要与其他可能需要维护您正在编写的代码的人交流什么。最重要的是,不透明对象是向库的用户指示库维护者绝对不保证对象的实现的 C 方式,除非该对象可以与文档化的函数一起使用。通过删除 void*,您基本上是在向世界宣布,“我宣布这个曾经不透明的实现是稳定的。”这可能不是你想要的。

      其次,恕我直言,您提出的解决方案是一种没有人高兴的半解决方案,更好的方法是开发一个包装类。这还有一个额外的好处,就是允许您在类的构造函数和析构函数中包装不可避免地伴随 C 风格不透明对象的 init 和 destroy 函数。这将允许您为您的客户提供资源管理和类型安全,而无需做更多工作。

      【讨论】:

      • 我不明白为什么结构指针不是不透明的。没有定义客户端可以访问的结构(或实现,就此而言)。关于包装类,这是针对纯 C 使用者的。
      • 看起来我对示例使用 C++ 结构并且标题显示 C++ 的事实感到困惑。此外,我建议不要将结构 OpaqueObjectInternal_ 命名为 Internal 和尾随下划线都是指示私有实现的常见约定。没有仔细阅读 cmets 让我相信这个结构是内部实现而不是不透明的指针。也许我们俩都可以从中吸取教训;-)
      • 有人将标题从 C 编辑为 C++。你会给这个结构起什么名字? C 接口知道的每种类型都有不同的结构。
      • 我只会把 Internal_ 砍掉。有时人们喜欢做类似 typedef struct typename_opaque_t * typename_handle;但这完全取决于你。
      猜你喜欢
      • 2011-02-12
      • 2011-07-15
      • 1970-01-01
      • 2016-06-30
      • 2020-08-04
      • 1970-01-01
      • 2013-07-12
      相关资源
      最近更新 更多