在C ++ 11中,我们知道std::string
保证是连续的并且以空值终止(或更加迂腐,由charT()
终止,在char
的情况下是空字符0)。
我需要使用这个C API,通过指针填充字符串。它写入整个字符串+ null终止符。在C ++ 03中,我总是被迫使用vector<char>
,因为我不能假设string
是连续的或空终止的。但是在C ++ 11中(假设一个正确符合的basic_string
类,在某些标准库中仍然是不合适的),我可以。
或者我可以吗?当我这样做时:
std::string str(length);
字符串将分配length+1
个字节,最后一个由空终止符填充。非常好。但是,当我将其传递给C API时,它将写入length+1
个字符。它将覆盖null终止符。
不可否认,它将使用空字符覆盖null-terminator 。这种情况很有用(事实上,我无法想象无法工作)。
但我并不关心“有效”。我想知道,根据规范,是否可以用空字符覆盖null终止符?
答案 0 :(得分:25)
不幸的是,这是UB,如果我将措辞解释正确(无论如何,它是不允许的):
§21.4.5 [string.access] p2
返回:
*(begin() + pos)
ifpos < size()
,否则引用类型为T
且价值为charT()
的对象; 不得修改参考值。
(编辑错误,它说T
而非charT
。)
.data()
和.c_str()
基本上回到operator[]
(§21.4.7.1 [string.accessors] p1
):
返回:指针
p
,p + i == &operator[](i)
中的每个i
[0,size()]
。
答案 1 :(得分: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”方法,它运行正常。)
答案 2 :(得分:9)
LWG 2475通过编辑operator[](size())
的规范(以粗体显示插入的文字)使其有效:
否则,返回对值为
charT
的对象的引用charT()
,将对象修改为charT()
以外的任何值 导致未定义的行为。
答案 3 :(得分:5)
我认为n3092不再是现在,但这就是我所拥有的。第21.4.5节允许访问单个元素。它需要pos&lt; = size()。如果pos&lt; size()然后你得到实际的元素,否则(即如果pos == size())那么你得到一个不可修改的引用。
我认为就编程语言而言,即使新值与旧值相同,也可以将一种可以修改该值的访问视为修改。
g ++是否有可以链接的迂腐图书馆?