11

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

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

4

10 回答 10

18

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

于 2008-12-02T21:07:08.310 回答
13

shared_ptr<>该语言的一部分,自 TR1 发布以来。见:(TR1)

于 2008-12-02T20:46:19.630 回答
6

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

于 2008-12-02T20:40:37.023 回答
6

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

我个人认为你应该避免在你的库的公共接口中使用太多时髦的 c++,因为它会给客户端带来很多问题。

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

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

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

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

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

这种方法肯定会让你的生活在很多方面变得更加复杂,但它是一种减少人们避开你的库的可能性,因为它不可能与他们自己的代码成功链接。

于 2008-12-02T22:13:09.457 回答
4

这是 C++。你知道,你可以在共​​享指针实现上模板化接口类。

于 2008-12-02T20:36:57.623 回答
3

您可以使用boost 复制实用程序来构建只有智能指针类的自定义版本的 boost。由于智能指针类是一个只有头文件的库,这应该会产生一些可以包含在库中的头文件。

于 2008-12-02T21:06:03.990 回答
3

这是一个有趣的问题,我已经有一段时间了。您是强迫用户使用您提供的任何库,还是让他们决定在他们的项目中什么是最好的?与往常一样,问题是您提供什么以及您对用户的要求。

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

现在,如果您使用智能指针,您将把您的解决方案强加给用户。如果他们计划使用他们自己版本的智能指针(例如您使用 boost::shared_ptr 并且他们想要 std::tr1::shared_ptr),如果他们与您的界面一起使用,他们将不再被允许使用它。无论您决定使用哪种智能指针(除了特殊的 std::auto_ptr 之外),您不仅在强制解决方案,而且还强制解决它所存在的问题。

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

作为旁注,boost::shared_ptr(boost 1.33+)在大多数情况下是线程安全的,并且在许多平台上使用无锁实现。无论如何,这应该让您对应该考虑的事情有所了解。

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

于 2008-12-02T21:43:11.200 回答
2

boost::intrusive_ptr也许?

于 2008-12-02T20:40:25.743 回答
1

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

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

于 2010-07-22T02:27:29.057 回答
1

使用auto_ptr或坚持使用 C 接口。强制 C++ 库进入你的界面总是丑陋的,扼杀了跨平台的任何机会,并为具有不同“下游”配置的客户带来维护噩梦。

一旦 C++0x 对您的客户来说足够主流,就切换到std::shared_ptr.

于 2010-07-22T02:36:06.837 回答