39

在 C++11 中,我们知道它std::string保证是连续的和空终止的(或者更迂腐的是,由 终止charT(),在这种情况下char是空字符 0)。

我需要使用这个 C API 来通过指针填充字符串。它写入整个字符串 + 空终止符。在 C++03 中,我总是被迫使用 a vector<char>,因为我不能假设它string是连续的或空终止的。但是在 C++11 中(假设一个正确符合的basic_string类,在某些标准库中仍然存在问题),我可以。

或者我可以吗?当我这样做时:

std::string str(length);

该字符串将分配length+1字节,最后一个由空终止符填充。那挺好的。但是当我把它传递给 C API 时,它会写length+1字符。它将覆盖空终止符。

诚然,它将用一个空字符覆盖空终止符。这很有可能会起作用(事实上,我无法想象它是如何不起作用的)。

但我不在乎什么“有效”。我想知道,根据规范,是否可以用空字符覆盖空终止符?

4

4 回答 4

25

不幸的是,这是 UB,如果我解释正确的措辞(无论如何,这是不允许的):

§21.4.5 [string.access] p2

返回: *(begin() + pos) if ,否则为valuepos < size()类型对象的引用;参考值不得修改TcharT()

(它说T不是的编辑错误charT。)

.data()并且.c_str()基本上指向operator[]§21.4.7.1 [string.accessors] p1):

返回:一个指针p,使得p + i == &operator[](i)对于每个iin [0,size()]

于 2012-10-05T06:44:31.370 回答
11

根据规范,覆盖终止NUL应该是未定义的行为。因此,正确的做法是在字符串中分配length+1字符,将字符串缓冲区传递给 C API,然后resize()返回length

// "+ 1" to make room for the terminating NUL for the C API
std::string str(length + 1);

// Call the C API passing &str[0] to safely write to the string buffer
...

// Resize back to length
str.resize(length);

(FWIW,我在 MSVC10 上尝试了“覆盖 NUL”的方法,效果很好。)

于 2012-10-05T08:36:16.727 回答
10

LWG 2475通过编辑operator[](size())(以粗体插入的文本)的规范使其有效:

否则,返回对charT具有 value 类型的对象的引用charT(),其中将对象修改为charT() 导致未定义行为之外的任何值。

于 2016-12-24T04:54:52.963 回答
5

我想 n3092 不再是最新的,但这就是我所拥有的。第 21.4.5 节允许访问单个元素。它需要 pos <= size()。如果 pos < size() 那么你得到实际元素,否则(即如果 pos == size())那么你得到一个不可修改的参考。

我认为就编程语言而言,即使新值与旧值相同,一种可以修改值的访问也被视为修改。

g++ 是否有可以链接到的迂腐库?

于 2012-10-05T06:33:16.643 回答