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,否则不得不分配动态数组。