在库的公共接口中使用boost :: shared_ptr

时间:2008-12-02 20:31:27

标签: c++ api boost shared-ptr

我们有一个C ++库,我们提供给几个不同的客户端。最近我们改用了在公共接口中使用原始指针而不是使用boost :: sharedptr。正如您可能猜到的那样,这提供了巨大的好处,因为现在客户不再需要担心谁需要删除什么以及何时删除。当我们进行切换时,我认为这是正确的做法,但是让我感到困扰的是我们必须在公共界面中包含来自第三方库的内容 - 如果可以的话,通常会避免这种情况。我认为提升实际上是C ++语言的一部分,我们的用例要求客户端代码和库都保存指向对象的指针。然而,最近我们的一个客户问我们是否可以切换到在界面中使用中性智能指针类,因为我们的库基本上强迫他们使用特定版本的boost - 这一点我当然理解和欣赏。所以现在我想知道什么是最好的行动方案。我已经考虑了一下,并想知道如何创建一个简单的智能指针类,它只是一个真正的提升智能指针。但是客户端可能会立即将其中一个填充到boost :: sharedptr中,然后我们将深入分析三个 - 这可能是一个问题,或者可能不是。无论如何,我很想听听社区关于解决这个问题的最佳方法的一些意见。

编辑:我最初说的是所有权转让,但我应该指明API边界两边的代码需要保存一个指向该对象的指针。

10 个答案:

答案 0 :(得分:18)

一种可能的解决方案是将boost :: shared_ptr与您的项目一起发布。由于它全部由标题组成,这将使您的客户不必手动安装boost库。您可以使用bcp来获取特定boost库所需的所有文件,包括库本身。当我在当时为一家公司工作并且需要boost::shared_ptr时,我做到了这一点,并且它确实起了很大作用。

答案 1 :(得分:13)

的shared_ptr<>截至TR1发布时,语言的一部分。 请参阅:(TR1)

答案 2 :(得分:6)

如果语义真的是所有权转移,为什么不使用auto_ptr,因为它是标准的C ++?在内部,您仍然可以从auto_ptr构建shared_ptr,然后在需要时拥有共享所有权。

答案 3 :(得分:6)

首先,如果您将库分发为源代码而不是编译库,则可以忽略此答案。还有一些特定于Windows的问题可能与其他平台无关。

我个人认为你应该避免在你的库的公共界面中有太多时髦的c ++,因为它会在客户端引起很多问题。

我不确定这对您的特定示例有多适用,但我个人遇到的问题是,当我升级到新版本时,我使用的stl库中的符号与第三方库中的符号冲突。这意味着我们在陌生的地方遇到了崩溃,我不得不做很多伎俩来避免这个问题。最后,由于这个原因,我继续使用旧版本的库。

您可能遇到的另一个问题是,不同的c ++编译器会以不同方式破坏相同的符号,这意味着即使它们使用相同的Boost版本,您也可能需要为每个要支持的编译器提供单独的库。查看“Imperfect C ++”一书,对此进行讨论。

在当前不同C ++编译器和环境的世界中,我认为可悲的事实是,您应该避免在界面中使用除C以外的任何内容,并确保动态链接您的库(以避免链接客户链接库时发生冲突, Windows运行时库在这里可能是一个真正的痛苦)。您仍然可以根据需要在库内部使用boost和fancy c ++,因为所有符号都将与dll中的客户环境隔离。

如果您真的想在库的界面中拥有智能指针和其他不错的C ++功能,请构建一个便于分发源代码的图层。这将确保它始终在客户环境中编译。然后,该接口以巧妙的方式调用暴露的C函数。我不认为在该层中使用boost是一个好主意,因为它会迫使客户采用它,即使他们不想要,但是它很容易替换它或找到另一个解决方案,因为该层作为源分发代码。

另一个不错的功能是,如果你想将你的库暴露给C / C ++之外的其他语言,那么在dll中调用C函数通常比使用奇怪名称修改的c ++函数更容易。

这种方法肯定会让你的生活在很多方面变得更加复杂,但这是一种让人们不太可能避开你的图书馆的方法,因为它无法与他们自己的代码成功联系。

答案 4 :(得分:4)

这是C ++。您知道,您可以通过共享指针实现模板化接口类。

答案 5 :(得分:3)

您可以使用boost copy实用程序来构建仅具有智能指针类的自定义版本的boost。 由于智能指针类是一个仅限标题的库,因此这应该会产生一些可以包含在库中的标题。

答案 6 :(得分:3)

这是一段有趣的问题。您是否强迫您的用户进入您提供的任何库,或者让他们决定他们项目中最好的库?与往常一样,问题是您提供什么以及您需要用户提供什么。

如果使用原始指针,则允许各种可能性。用户代码可以使用原始指针,将其存储到std :: auto_ptr,shared_ptr(无论是boost还是TR1),还是他们自制的智能指针版本。但是如果他们忘记释放内存,这也可能让用户遇到麻烦,如果他们只是想要为方法调用创建一个临时代码,它需要更多的代码(如果你提供原始指针,他们将不得不存储指针在非临时[可能是智能]指针变量中。)

现在,如果您使用智能指针,则会强制您的解决方案进入用户。如果他们计划使用他们自己的智能指针版本(比如你使用boost :: shared_ptr并且他们想要std :: tr1 :: shared_ptr),那么如果他们使用你的界面,就不再允许他们使用它。无论你决定使用哪种智能指针(除了特殊的std :: auto_ptr),你不仅要强制解决问题,还要解决问题。

如果您的用户具有多线程应用程序,并且您的解决方案不是线程安全的,则用户必须使用不安全的解决方案。另一方面,如果智能指针是线程安全的但是会产生锁定成本,即使这些成本在多线程应用程序中工作,也会将这些成本推送给用户。如果你编译你的库(不是只有头文件库)那么你不仅强迫一种智能指针,而且还强制它的特定版本,因为智能指针库中的任何更改都将破坏你的代码的兼容性。

作为旁注,在大多数情况下,boost :: shared_ptr(boost 1.33+)是thread safe,它在许多平台中使用无锁实现。无论如何,这应该让你了解你应该考虑的事情。

最后,您必须考虑到您不仅要将用户绑定到使用智能指针类型,还要使用相同版本的智能指针。如果针对特定版本的boost编译lib,则用户将绑定到该特定实现o

答案 7 :(得分:2)

答案 8 :(得分:1)

引入boost :: shared_ptr会强制您的客户端使用boost。对某些人来说,这是一个小问题。

如果您的lib作为已编译的二进制文件分发,它还会强制您的客户端使用您的lib使用的相同编译器。或者,如果您的库是以源代码分发的,那么客户端必须坚持使用自己选择的用于编译lib的编译器。对于任何相当规模的项目来说,这都不是一个小问题。

答案 9 :(得分:1)

使用auto_ptr或坚持使用C接口。强制C ++ libs进入你的界面总是很难看,杀死任何跨平台的机会,并导致具有不同“下游”配置的客户的维护噩梦。

只要C ++ 0x对您的客户来说足够主流,请切换到std::shared_ptr