std::string被移动后,其c_str()返回的数据是否仍有效?
这种异步发送字符串的写法是否安全?
问题背景
假设有一个异步发送const char*数据的函数sendData,完成或出错时触发回调(省略错误处理):
void sendData( const char *data, std::function<void()> );
要求在回调触发前,必须保证传入的数据有效。现有一种实现方案:传入std::string::c_str()的结果,并将该string移动到回调lambda中:
void send( std::string str ) { auto data = str.c_str(); sendData( data, [st=std::move(str)]() {} ); }
这里str被移动到lambda中,回调结束时会销毁该string。当然也可以将string转移到std::unique_ptr<std::string>再移入lambda,但上述代码更简洁。请问这种写法是否安全?
结论:这种写法完全安全
具体分析:
- 移动操作的关键细节:当执行
auto data = str.c_str();时,data指向原str内部字符数组的地址。随后std::move(str)把str的资源转移给lambda捕获的st,此时原str会变成“有效但未定义状态”,但std::string的移动语义会保证:被移动后的源对象不会释放原内存资源——因为资源已经完全转移给了st。 - 数据有效性的核心保障:lambda被
std::function持有,会一直存活到异步操作完成、回调触发为止。而st作为lambda的成员,持有原字符串的全部资源,data指向的地址就是st内部的字符数组地址。只要回调没执行完,st就不会被销毁,data指向的内存就始终有效。 - 无需额外包装unique_ptr:
std::string的移动语义已经完美实现了资源所有权的转移,效果和用unique_ptr<std::string>包装后移入lambda完全一致。直接移动string的写法更简洁,没必要多此一举。
内容的提问来源于stack exchange,提问作者Slava
相关产品推荐
相关产品推荐

