使用& front()修改std :: string中的基础字符数组

时间:2015-12-16 13:36:17

标签: c++ c++11

我必须在我的一个程序中与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中明确禁止修改。

2 个答案:

答案 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的解释,这种方法应该是合法的。