围绕共享库边界的C ++接口设计

时间:2011-08-03 14:51:17

标签: c++ design-patterns stl shared-libraries

假设我有两个项目。一个是应用程序,另一个是共享库,包含可以由不仅仅是这个应用程序使用的通用,可重用的代码。

我的应用程序使用STL,我的共享库也使用STL。这里的第一个问题是我的共享库正在使用STL。如果我在我的应用程序中构建了一个较新版本的STL,但我没有重建我的共享库,因为没有必要,那么我们马上就会遇到兼容性问题。

我首先想到解决这个问题的方法是在共享库类的接口中根本不使用STL。假设我的库中有一个函数,它接受一个字符串并用它做一些事情。我会让函数原型看起来像:

void DoStuffWithStrings( char const* str );

而不是:

void DoStuffWithStrings( std::string const& str );

对于字符串,这可能在不同版本的STL之间是正常的,但缺点是我们从std::stringchar*,然后回到std::string,这似乎是它会导致性能问题。

是否建议将原始类型的装箱/拆箱装入他们的STL对应物?当我们尝试对std::list执行此操作时,这会变得更糟,因为实际上没有“原始类型”我知道我们可以轻松地传递它,而无需执行某种O(n)或类似的操作

在这种情况下哪些设计效果最好?每个人的利弊是什么?

4 个答案:

答案 0 :(得分:3)

const char*方法的一个优点是你的库也可以从C调用,因此也可以从很多其他语言中调用C语言(几乎所有的东西)。仅这一点就是一个非常有趣的卖点。

但是,如果您编写和维护这两个库,并且它们将仅在C ++中使用(比如未来5年),我就不会经历转换所有内容的麻烦。 std::string是一回事,std::vectorstd::map不会转换得很好。除此之外,你有多少次转向另一个STL实施?在这些情况下,您是否真的要“忘记”重建您的共享库?此外,如果确实需要,您仍然可以编写/生成C样式包装器。

结论(偏向于我对这件事的经历):如果你不需要C,那就去吧。

答案 1 :(得分:2)

当然,标准C ++库应该被视为C ++ ABI的一部分,就像虚拟表格布局或名称修改方案一样。此外,ABI中任何不兼容的更改都更有可能影响模糊的边角情况,而不是std :: vector的布局。换句话说:如果你要创建一个C ++库,可以随意使用标准的C ++类。

答案 2 :(得分:1)

如果库使用与应用程序不同的堆,则可能会出现另一个问题。如果是这种情况或可能是这种情况,请确保库拥有/管理自己的内存。当库使用不同的c库并因此使用不同的malloc / free并因此使用不同的堆时,多个堆可能是一个问题。 http://msdn.microsoft.com/en-us/library/ms810466.aspx

答案 3 :(得分:0)

许多A.P.I.和共享库使用“opaque”或通用指针作为函数中的参数,以避免版本之间的差异。

// this:
int MyFunc(char* Param1, int Param2, bool Param3);

// into this:
struct MyParams
{
  char* Param1;
  int Param2;
  bool Param3;
}

// "Params" its really "struct MyParams*"
int MyFunc(void* Params);

有时如果共享库函数有多个参数,它们会替换为指针,taht应该是指向数组或结构甚至是类的指针。

这取决于你如何使用你的库,因为许多库像普通的C一样使用,即使你使用的是C ++。