我必须在我的一个程序中与C库接口,我正在编写一个瘦包装器来使用C ++类型,例如std::string
。有许多函数接受char*
和最大长度作为参数,并使用零终止的C字符串覆盖char*
指向的内存。传统上,我使用堆栈数组并手动将数据复制到字符串中。
std::string call_C_function(int x) {
char buf[MAX_LEN] = {0}; // MAX_LEN is defined by the library
size_t len = MAX_LEN;
C_function(x, buf, &len);
return std::string(buf, len);
}
我试图避开副本并提出解决方案,但我不知道这是否严格合法:
std::string call_C_function(int x) {
std::string buf(MAX_LEN, '\0'); // MAX_LEN is defined by the library
size_t len = MAX_LEN;
C_function(x, &buf.front(), &len);
buf.resize(len);
return buf;
}
这编译并运行,但我有疑问,因为std::string
类使得很难获得一个指向字符数据的非const指针。 c_str()
和data()
都返回const指针。该标准明确禁止对这些函数修改缓冲区:
21.4.7.1:程序不得改变存储在字符数组中的任何值。
从文档中看,这似乎是合法的,因为front()
返回对缓冲区的第一个字符的引用,该引用必须是连续的(我正在使用C ++ 11/14)。在21.4.5中,front()
的语义是用operator[](0)
来定义的,它不禁止修改。
从语言标准的角度来看,这种方法有什么问题吗?似乎这将是一个循环漏洞,允许在21.4.7.1中明确禁止修改。
答案 0 :(得分:4)
这很好。您不能通过从const
成员函数返回的指针修改字符串,但这并不意味着您根本不允许修改字符串。你有一个非const字符串,所以你可以修改它。原则上它与s[0] = 'a'; s[1] = 'b';
等没有什么不同。
禁止覆盖存储在字符串数据之后的最终'\0'
,但我假设从您的示例中MAX_LEN
包含由C函数写入的空终止符的空格,所以C函数只会覆盖字符串内容,而不会覆盖之后存储的额外字符。
有一个未解决的问题(LWG 2391)建议添加一个等同于std::string::data()
的非常量&s.front()
,并且会让您直接访问而不会让您担心去违背图书馆的意图。
答案 1 :(得分:3)
根据我对C ++ 11的解读:
const charT& front()const;
图表&安培;前();
需要:!empty()
效果:等同于operator [](0)。
让我们看一下operator []:
const_reference运算符[](size_type pos)const;
引用运算符[](size_type pos);
1需要:pos< = size()。
2如果pos<返回:*(begin()+ pos) size(),否则引用 类型为T的对象,带有valuecharT();参考值不得修改。
由于您预先分配了缓冲区,pos
将小于size()。 begin()返回一个迭代器,因此所有常用的迭代器特性都适用。
因此,根据我对C ++ 11的解释,这种方法应该是合法的。