在处理必须与 C 代码互操作的代码时,我经常遇到这个问题,其中有一个
std::string
,您需要将其内容复制到纯字符缓冲区,如下所示:
struct T
{
int i;
char cstr[size + 1];
};
// `std::` removed here for clarity only.
void f(vector<pair<int, string>> const& in)
{
T* out = new/malloc whatever.
for (size_t i = 0; i < in.size(); ++i) {
out[i].i = in[i].first;
strncpy(out[i].cstr, in[i].c_str(), sizeof(out[i].cstr));
}
// whatever
}
但是,这很不方便,也不太具有表现力。我更愿意做一些更类似于:
void f(vector<pair<int, string>> const& in)
{
T* out = new/malloc whatever.
for (size_t i = 0; i < in.size(); ++i)
out[i] = T{ in[i].first, in[i].c_str() };
// whatever
}
如何解决这个“字符串复制问题”?唯一的解决方案是通过一个能够包装 c 数组的对象,以便运算符=“做正确的事情”,以启用如下模式:
void f(vector<pair<int, string>> const& in)
{
T* out = new/malloc whatever.
for (size_t i = 0; i < in.size(); ++i)
std::tie(out[i].id, WRAPPER(out[i].cstr)) = in[i];
// whatever
}
语言或标准库中是否有任何内容已经解决了“那个问题”?或者我唯一的选择是用正确的语义构建我自己的类? (我自己知道怎么做;我问是否已经做了一些东西)。
我更喜欢继承 C
struct
并添加一个转换构造函数。
示例:
struct T {
int i;
char cstr[size + 1];
};
struct T2 : T {
T2(const std::pair<int, std::string>& pair) : T{pair.first} {
std::strncpy(cstr, pair.second.c_str(), sizeof cstr);
cstr[sizeof cstr - 1] = '\0';
}
};
这样,您的 C++ 代码就可以获得更多表现力:
void f(std::vector<std::pair<int, std::string>> const& in) {
std::vector<T2> out(in.begin(), in.end());
//...
}
然后,您可以将
T2
切片为 T
,并根据需要提供指向每个元素的指针:
for (T& t : out) { // slice
std::cout << t.i << ' ' << t.cstr << " ptr: " << &t << '\n';
}
或者使用
out.data(), out.size()
调用 C 函数,如下所示:
// a C function
void foo(T* ts, size_t size) {
for(size_t i = 0; i < size; ++i) {
printf("%d %s %p\n", ts[i].i, ts[i].cstr, (void*)&ts[i]);
}
}