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

2022-01-24 00:00:00 containers c++ api-design

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

When designing a C++ library, I read it is bad practice to include standard library containers like std::vector in the public interface (see e.g. Implications of using std::vector in a dll exported function).

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

What if I want to expose a function that takes or returns a list of objects? I could use a simple array, but then I would have to add a count parameter, which makes the interface more cumbersome and less safe. Also it wouldn't help much if I wanted to use a map, for example. I guess libraries like Qt define their own containers which are safe to export, but I'd rather not add Qt as a dependency, and I don't want to roll my own containers.

在库界面中处理容器的最佳做法是什么?是否有一个可以用作胶水"的小型容器实现(最好只有一个或两个我可以放入的文件,具有许可的许可证)?或者有没有办法让 std::vector 等跨 .DLL/.so 边界并使用不同的编译器安全?

What's the best practice to deal with containers in the library interface? Is there maybe a tiny container implementation (preferably just one or two files I can drop in, with a permissive license) that I can use as "glue"? Or is there even a way to make std::vector etc. safe across .DLL/.so boundaries and with different compilers?

推荐答案

实际上,这不仅适用于 STL 容器,而且适用于几乎所有 C++ 类型(尤其是所有其他标准库类型).

Actually this is not only true for STL containers but applies to pretty much any C++ type (in particular also all other standard library types).

由于 ABI 不标准化,您可能会遇到各种麻烦.通常,您必须为每个受支持的编译器版本提供单独的二进制文件才能使其工作.获得真正可移植的 DLL 的唯一方法是坚持使用纯 C 接口.这通常会导致类似 COM,因为您必须确保所有分配和匹配的解除分配都发生在相同的模块,并且不会向用户公开实际对象布局的任何细节.

Since the ABI is not standardized you can run into all kinds of trouble. Usually you have to provide separate binaries for each supported compiler version to make it work. The only way to get a truly portable DLL is to stick with a plain C interface. This usually leads to something like COM, since you have to ensure that all allocations and matching deallocations happen in the same module and that no details of the actual object layout are exposed to the user.

相关文章