C++17中通过std::string非const data()重载修改内部缓冲区的行为是否良定义
C++17下std::string非const
data() 配合memcpy调用的良定义判定 前置背景
C++17对std::string的接口做了关键调整:新增了非const修饰的data()重载,签名为CharT* data() noexcept;,替换了之前仅返回const修饰指针的单版本接口。
判定结论
你给出的这段代码:
std::string str(some_size, '0'); memcpy((void*)str.data(), source, some_size);
在满足约束条件的前提下属于良定义行为。
详细说明
1. 非const data()的标准语义
C17起标准明确要求std::string的字符存储必须连续,非const版本的data()返回的指针直接指向底层可修改的字符存储首地址,不再是只读权限的const内存区域——这是和C17之前最核心的区别(C++17之前就算强转去掉const修饰写内存,也是明确的未定义行为)。
这个指针的有效期和str对象绑定,只要str没有触发内存重分配操作,指针就保持有效。
2. 调用合法的必要约束
这段代码不会触发未定义行为,必须同时满足以下条件:
- 构造
str时传入的大小some_size,和memcpy的拷贝长度完全一致,没有越界写入str的底层存储; source指向的内存块可读,且有效内存大小至少为some_size字节;source指向的内存区域和str的底层存储没有重叠——如果两个内存区重叠,哪怕其他条件都满足,memcpy本身的行为也是未定义的。
3. 常见的非法场景
以下情况会导致行为未定义,和data()接口本身的合法性无关:
- 构造
str后、调用memcpy前,对str执行了会触发重分配的操作(如追加字符、扩容、赋值更长的字符串等),此时之前获取的data()指针已经失效,属于野指针访问; - 实际
memcpy的拷贝长度超过str的当前实际容量,越界写入不属于str的内存区域; source是不可读的非法指针。
补充说明
代码里的(void*)str.data()属于冗余写法:非const版本的data()返回的本身就是char*类型,和memcpy第一个参数要求的void*完全兼容,不需要额外强制转换,也不影响最终的行为合法性。
内容的提问来源于stack exchange,提问作者Eshkod
相关产品推荐
相关产品推荐

