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

Using &front() to modify underlying character array in std::string

本文关键字:数组 字符 string 使用 front 修改 std      更新时间:2023-10-16

我必须在我的一个程序中与 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, ''); // 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类使得很难获得指向字符数据的非常量指针。 c_str()data() 都返回常量指针。该标准明确禁止修改这些函数的缓冲区:

21.4.7.1: 程序不得更改字符数组中存储的任何值。

从文档中看,这似乎是合法的,因为front()返回对缓冲区第一个字符的引用,该字符必须是连续的(我使用的是 C++11/14(。在 21.4.5 中,front() 的语义是根据不禁止修改的operator[](0)定义的。

从语言标准的角度来看,这种方法有什么问题吗?这似乎是一个漏洞,允许在 21.4.7.1 中明确禁止修改。

很好。不允许通过从 const 成员函数返回的指针修改字符串,但这并不意味着根本不允许修改字符串。您有一个非常量字符串,因此您可以对其进行修改。原则上,这与做s[0] = 'a'; s[1] = 'b';等没有什么不同。

禁止覆盖字符串数据之后存储的最终'',但我从您的示例中假设MAX_LEN包含由 C 函数写入的 null 终止符的空间,因此 C 函数只会覆盖字符串内容,而不会覆盖之后存储的额外字符。

有一个未解决的问题(LWG 2391(建议添加一个等同于&s.front()的非常量std::string::data(),并且可以让您直接访问,而不会让您担心违背图书馆的意图。

根据

我对C++11的阅读:

const charT& front(( const;

字符和前线((;

需要: !空((

效果:等效于运算符 [](0(。

让我们看看运算符[]:

const_reference运算符[](size_type pos( const;

引用运算符[](size_type pos(;

1 要求:pos <= size((。

2 返回:*(begin(( + pos( 如果 pos

由于您预先分配了缓冲区,因此pos将小于 size((。 begin(( 返回一个迭代器,因此所有常用的迭代器特征都适用。

所以,根据我对C++11的解释,这种方法应该是合法的。