Effective STL [16] | 如何将 vector 和 string 的数据传给遗留的 API
string 和 vector 传递给 C API
vector 传递指针
C 风格 API 接受的是数组和 char*
指针,这样的 API 还会存在很长时间,如果有 1 个 vector 对象 randy, 则使用 &v[0]
就可以得到一个指向 randy 中数据的指针。对于 string 对象 sesame,则传递 sesame.c_str()
即可。
表达式 randy[0]
生产一个指向 vector 中第一个元素的引用,所以,&randy[0]
是指向那个首元素的指针。
vector 中的元素被 C++ 标准限定为存储在连续内存中,就像是一个数组。
所以我们可能会这么传递
|
|
唯一的问题就是,如果 randy 是空的,randysize()
是 0,而 &randy[0]
试图产生一个指向根本就不存在的东西的指针。
可以提前判断一下 randy 的大小:
|
|
randy.begin () 代替 & randy [0]?
对于 vector,其迭代器实际上是指针。
begin
的返回类型是 iterator
,而不是一个指针,当你需要一个指向 vector 内部数据的指针时绝不该使用 begin。如果你基于某些原因决定键入 randy.begin()
,就应该键入 &*randy.begin()
,因为这将会产生和 &v[0]
相同的指针。
string 传递指针
类似从 vector 上获取指向内部数据的指针的方法,对 string 不是可靠的:
- string 中的数据并没有保证被存储在独立的一块连续内存中
- string 的内部表示形式并没承诺以一个 null 字符结束。这解释了 string 的成员函数 c_str 存在的原因
即使是字符串的长度为 0,c_str
将返回一个指向 null
字符的指针。
在两种形式下,指针都被传递为指向 const 的指针。vector 和 string 的数据只能传给只读取而不修改它的 API。
如果你将 randy
传给一个修改其元素的 C 风格 API 的话,典型情况都是没问题,但被调用的函数绝不能试图改变 vector 中元素的个数。否则,randy 的内部状态将会变得不一致,v.size()
将会得到一个不正确的结果。
把一个 vector 传递给需要修改 vector 数据的 API,一定要确保这些额外限制继续被满足,比如是否需要保持原来 vector 中元素的顺序。
C 风格 API 返回的元素初始化 STL 容器
初始化 vector
利用 vector 和数组潜在的内存分布兼容性将存储 vecotr 的元素的空间传给 API 函数:
|
|
这个技巧只能工作于 vector,因为只有 vector 承诺了与数组具有相同的潜在内存分布。
初始化 string
只要让 API 将数据放入一个 vector<char>
,然后从 vector 中将数据拷到 string:
|
|
初始化其他 STL 容器
通用方法:C 风格 API 把数据放入一个 vector,然后拷到实际想要的 STL 容器
|
|
STL 容器传递给 C API
STL 容器将它们的数据传给 C 风格 API,只要将容器的每个数据拷到 vector,然后将 vector 传给 API:
|
|
如果在编译期就知道容器的大小,可以将数据拷进一个数组,然后将数组传给 C 风格的 API,否则不得不分配动态数组。

