当存在指向std::string的std::string_view且未被访问时,修改该std::string是否安全?
嘿,这个问题得拆成两部分唠,咱们结合你给的代码来掰扯清楚:
首先,修改std::string本身的操作肯定是安全的——std::string的所有成员函数(比如你代码里的clear())都是设计来保证自身状态合法的,不管有没有外部的std::string_view盯着它。哪怕有一百个string_view指向它,你调用clear()、append()、resize()这些操作,std::string自己都能正常工作,不会出内部状态混乱的问题。
但重点是:修改之后,那个还存在的std::string_view如果后续被访问,安全性就不一定了,得看你对std::string做了啥修改:
如果修改没触发
std::string内部缓冲区的重新分配(比如clear()、修改现有字符、把长度改小/改到不超过当前容量的大小):
这时候std::string_view保存的还是原缓冲区的起始地址,但它记录的长度是创建时的旧长度。比如你代码里如果把顺序反过来,先调用input.clear()再用input_v输出,那input_v会试图读取原缓冲区里的内容——但这时候std::string的有效长度已经是0了,缓冲区里的旧数据属于std::string不再维护的区域,读取它属于未定义行为,结果可能是输出乱码,也可能啥都没有,全看编译器和运行环境。如果修改触发了
std::string内部缓冲区的重新分配(比如往里面加超多字符,超过当前的容量):
这时候std::string会把旧缓冲区释放掉,重新申请一块新的内存。那之前的std::string_view就变成了“悬空视图”——它指向的内存已经被释放了,后续再访问它的话,轻则读垃圾数据,重则直接程序崩溃,妥妥的未定义行为。
回到你给的代码:echo函数里先输出了input_v(已经完成了对视图的访问),再调用input.clear(),这时候完全没问题——因为修改std::string的时候,那个string_view已经用完了,后续也没再访问它。但如果是先改std::string再用视图,就得小心踩坑。
总结一下:只修改std::string本身是安全的,但一定要注意后续别再用那个已经“过时”的std::string_view,不然大概率要出问题。
备注:内容来源于stack exchange,提问作者VL-80

