16.STL容器与C API

获取指针

</br>
假设有一个vector对象v,而你需要得到一个指向v中数据的指针,这让v可以被当作一个数组在C中使用。
我们只需要使用&v[0]即可获得指向首元素的指针。如果是string,请使用s.c_str().
实际上这样做可能会有一些问题,具体而言就是v可能是空的,所以需要先对v进行empty判定

有人说可以用begin这种迭代器来代替&v[0],实际上这完全是胡说八道,因为并不总是能做到迭代器和指针之间的互相转换。
&*v.begin()倒是真的可以等价于&v[0],但这种写法除了让别人一目了然你的智力水平外并没有其他好处。

有人会疑惑为什么vctor就可以直接取址,而string不行,原因有以下两点:

  1. string的数据并没有保证被存储于连续内存(详见 Effective STL 15)
  2. string并不保证以null结尾

因此,string必须使用c_str:

1
2
void doSomething(const char *pString);
void doSomething(s.c_str());

C API初始化STL容器

用C API返回的元素初始化vector

1
2
3
4
5
// C API数需要一个指向数组的指针,数组最多有arraySize个double
// 功能为向数组内部写入数据,返回写入数据的个数
size_t fillArray(double *pArray, size_t arraySize);
vector<double> vd(maxNumDoubles);,
vd.resize(fillArray(&vd[0], vd.size()));//数据写入后调整大小

用C API返回的元素初始化string

上述写法并不能应用于string类型,因为只有vector保证了与数组具有相同内存分布。(顺序表)
但用用C API初始化string也不难,具体来说就是先初始化一个vector<char>,然后再用vector初始化string:

1
2
3
4
size_t fillString(char *pArray, size_t arraySize);
vector<char> vc(maxNumChars);
size_t charsWritten = fillString(&vc[0], vc.size());
string s(vc.begin(), vc.begin()+charsWritten);

用C API返回的元素初始化STL中的任何容器

因为和数组内存分布一致的只有vector,所以我们的策略十分简单:把数组内的元素传入vector,然后再用vector初始化STL容器:

1
2
3
4
5
6
size_t fillArray(double *pArray, size_t arraySize);
vector<double> vd(maxNumDoubles);
vd.resize(fillArray(&vd[0], vd.size()));
deque<double> d(vd.begin(), vd.end()); // 拷贝数据到deque
list<double> l(vd.begin(), vd.end()); // 拷贝数据到list
set<double> s(vd.begin(), vd.end()); // 拷贝数据到set


STL容器传递数据至C API

</br>
从上文中自然能领会到反向传递的方法:用STL容器内的元素初始化vector,然后再用vector传入C API:

1
2
3
4
void doSomething(const int* pints, size_t numInts);
set<int> intSet; //要传递给API数据的set
vector<int> v(intSet.begin(), intSet.end());
if (!v.empty()) doSomething(&v[0], v.size());