覆盖 std::string 的空终止符是否合法?

问题描述 投票:0回答:4

在 C++11 中,我们知道

std::string
保证是连续的并且以空字符结尾(或者更迂腐地,以
charT()
结尾,在
char
的情况下是空字符 0)。

我需要使用这个 C API,它通过指针填充字符串。它写入整个字符串+空终止符。在 C++03 中,我总是被迫使用

vector<char>
,因为我无法假设
string
是连续的或空终止的。但在 C++11 中(假设有一个正确符合标准的
basic_string
类,这在某些标准库中仍然不确定),我可以。

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

std::string str(length);

该字符串将分配

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

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

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

c++ c++11 language-lawyer stdstring
4个回答
25
投票

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

§21.4.5 [string.access] p2

返回:

*(begin() + pos)
(如果为
pos < size()
),否则为对
T
类型且值为
charT()
的对象的引用; 参考值不得修改

(编辑错误,它说

T
而不是
charT
。)

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

返回: 一个指针

p
,使得
p + i == &operator[](i)
对于
i
中的每个
[0,size()]


13
投票

LWG 2475 通过编辑

operator[](size())
的规范使其有效(以粗体插入文本):

否则,返回对具有值的

charT
类型对象的引用
charT()
,将对象 修改为
charT()
以外的任何值 导致未定义的行为。


10
投票

根据规范,覆盖终止

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”方法,效果很好。)


编辑 2024-FEB-27:自 2012 年(最初在此提出并回答此问题的年份)以来,C++ 标准已被修改,并且 自 C++17 起,覆盖

std::string
是合法的
NUL
终结者与另一个
NUL


5
投票

我想 n3092 不再是最新的,但这就是我所拥有的。第 21.4.5 节允许访问单个元素。需要 pos <= size(). If pos < size() then you get the actual element, otherwise (i.e. if pos == size()) then you get a non-modifiable reference.

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

g++ 有一个可以链接的迂腐库吗?

© www.soinside.com 2019 - 2024. All rights reserved.