在C++库接口中安全地使用容器

jdm*_*jdm 12 c++ containers api-design

在设计C++库时,我认为std::vector在公共接口中包含标准库容器是不好的做法(参见例如在dll导出函数中使用std :: vector的含义).

如果我想公开一个获取或返回对象列表的函数,该怎么办?我可以使用一个简单的数组,但后来我必须添加一个count参数,这使得界面更麻烦,更不安全.map例如,如果我想使用a ,它也无济于事.我想像Qt这样的库定义了自己的容器,这些容器可以安全地导出,但是我宁愿不把Qt作为依赖项添加,而且我不想滚动自己的容器.

在库接口中处理容器的最佳做法是什么?是否可能有一个小容器实现(最好只有一两个文件,我可以使用许可许可证),我可以用作"粘合剂"?或者甚至有一种方法可以使std::vector.DLL/.so边界和不同的编译器安全等等?

Joh*_*nck 4

您可以实现模板功能。这样做有两个优点:

  1. 它可以让您的用户决定他们想要在您的界面中使用哪种类型的容器。
  2. 它使您不必担心 ABI 兼容性,因为您的库中没有代码,它将在用户调用函数时实例化。

例如,将其放入头文件中:

template <typename Iterator>
void foo(Iterator begin, Iterator end)
{
  for (Iterator it = begin; it != end; ++it)
    bar(*it); // a function in your library, whose ABI doesn't depend on any container
}
Run Code Online (Sandbox Code Playgroud)

然后,您的用户可以使用任何容器类型调用 f​​oo,甚至是他们发明的您不知道的容器类型。

一个缺点是您需要公开实现代码,至少对于 foo.

编辑:您还说过您可能想退回一个容器。考虑像回调函数这样的替代方案,就像 C 语言的黄金时代一样:

typedef bool(*Callback)(int value, void* userData);
void getElements(Callback cb, void* userData) // implementation in .cpp file, not header
{
  for (int value : internalContainer)
    if (!cb(value, userData))
      break;
}
Run Code Online (Sandbox Code Playgroud)

这是一种相当老式的“C”方式,但它为您提供了一个稳定的接口,并且基本上任何调用者都非常可用(甚至是经过微小更改的实际 C 代码)。这两个怪癖是 void* userData 让用户在其中插入一些上下文(比如他们是否想要调用成员函数)和 bool 返回类型让回调告诉您停止。您可以使用 std::function 或其他任何方式使回调更加精美,但这可能会破坏您的一些其他目标。

  • 我可以建议“函数模板”而不是“模板函数”吗?:) (2认同)