std::basic_string::data
在its specification下有一个要求。
[string.accessors] (强调我的意思)
const charT* c_str() const noexcept; const charT* data() const noexcept;
1 返回:指针
p
,使得p + i == &operator[](i)
中每个i
的{{1}}。2 复杂度:恒定时间。
3 要求:程序不得更改存储在字符数组中的任何值。
在C ++ 03中,[0, size()]
很有意义,因为它不必返回指向实际字符串缓冲区的指针,而对于c_str
,则因为COW是可能的实现策略,因此它没有返回指针。即使缓冲区不是真正的常量,修改data
也会干扰COW的不变性。
但是由于不允许使用C ++ 11 COW,因此data
和c_str
返回相同的指针,并且它指向允许修改的缓冲区data
。为什么然后通过operator[]
修改指针仍然显式未定义行为?有实际原因吗?
答案 0 :(得分:8)
我不是在谈论常量
。std::string
,而是非常量
这就是为什么存在该语句的原因(甚至在C ++ 17中,当添加了非{const
data
时,它仍然存在)。因为data
不知道。
在优化的小字符串string
实现中,string
对象本身存储字符数组。如果该string
对象被声明为const
,则其子对象也是如此。 Modifying objects declared as const
is UB。
相反,vector::data
没有这样的语句,因为const vector
总是 堆分配其数组。因此,虽然数组从外部逻辑上const
,但从技术上讲它是定义良好的(但实际上,真的不应)从{ {1}} const_cast
,因为您正在修改一个未创建为const
的对象。
如果vector::data
没有这样的声明,则基于SSO的实现将是不可能的,因为修改const
的元素是合法,就像修改basic_string::data
的元素是合法的。但是修改它不是合法的,因为它可能是一个const string
对象,其数据存储在内部。