编辑:对不起大家,我不认为这个玩具示例真正反射(reflect)了我的问题。我应该问的是是否有办法释放 std::string 对象的缓冲区。没有,这是有道理的。谢谢!
假设我有以下(损坏的)代码:
void get_some_data(MyCustomContainer& val)
{
std::string mystr = some_function();
val.m_data = &mystr[0];
}
这是行不通的,因为 mystr
指向的内存在 get_some_data
结束时被释放,val.m_data 引用的内存将无效。
我如何告诉 std::string “不要在析构函数中释放内存缓冲区!” ?我不想复制数据。 MyCustomerContainer 对象将在其析构函数中处理内存释放。
最佳答案
你不能在不违反规则的情况下这样做。 std::string
类不允许显式释放其所有权。事实上,由于 SBO 优化,std::string
甚至可能没有分配任何内存:
std::string str1 = "not allocating";
std::string str2 = "allocating on the heap, the string is too large";
此行为完全依赖于平台和实现。如果字符串未在堆上分配其缓冲区,则数据将放在堆栈上,不需要取消分配。
{
std::string str1 = "not allocating";
} // no buffer freed
所以即使有办法告诉字符串不要取消分配它的缓冲区,也没有办法判断缓冲区是否在堆上管理。
即使有办法判断字符串是否使用堆栈,您也必须作为类成员分配一个缓冲区并复制其内容。
传输字符串的数据并窃取其对该字符串的内存资源的所有权的想法从根本上被打破了,因为如果不复制就无法逃脱,仅仅是因为可能没有所有权可以窃取。
如果您不想更改 MyCustomContainer
的工作方式,我建议您在所有情况下都复制字符串内容:
void get_some_data(MyCustomContainer& val)
{
std::string mystr = some_function();
val.m_data = new char[mystr.size()];
std::memcpy(val.m_data, mystr.data(), mystr.size());
}
相比之下,如果您允许 MyCustomContainer
存储 std::string
,当通过移动字符串分配缓冲区时,您实际上可以不用复制就可以逃脱:
void get_some_data(MyCustomContainer& val)
{
// let m_data be a std::string
val.m_data = some_function();
// The above is equivalent to this:
// std::string mystr = some_function();
// val.m_data = std::move(mystr);
}
移动字符串将调用移动赋值。通过移动分配,字符串实现会将 mystr
缓冲区的所有权转移到 m_data
中。这将防止任何额外分配。
如果 mystr
没有分配,那么移动分配将简单地复制数据(因此那里也没有分配)。
关于c++ - 如何有效地将底层数据从 std::string 移动到另一种类型的变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48232355/