Jas*_*son -2 c++ string memory-management return-by-value
在以下代码中,字符串封装在类Foo中.
对Foo :: getText()的调用按值返回字符串.这将创建字符串对象的第二个实例,但现在两个字符串对象都指向堆上的相同char缓冲区.
删除Foo实例时,将自动销毁封装的字符串,因此将删除堆上的char缓冲区.
即使getText()按值返回字符串,生成的字符串对象仍依赖于原始字符串对象的生命周期,以便保留它们相互指向的char缓冲区.
这是不是意味着打印retval到终端是对堆已经免费的内存的无效访问?
class Foo
{
Foo(const char* text) :
str(text)
{
}
std::string getText()
{
return str;
}
std::string str;
};
int main()
{
Foo pFoo = new Foo("text");
std::string retval = foo.getText();
delete pFoo;
cout << retval; // invalid memory access to char buffer?
}
Run Code Online (Sandbox Code Playgroud)
我想很多人都认为,因为字符串是按值返回的,所以不需要关心Foo中原始字符串的生命周期.这个问题与字符串没有严格的关系,但实际上适用于任何具有封装指针的类,这些指针在销毁时是免费的.但是在弦乐方面,最好的做法是什么?
return std::string(retval.c_str());getText()?编辑:
我想我被RVO误导了.此示例中的所有三个字符串都在同一地址返回c_str.RVO应该受到指责吗?
class Obj
{
public:
Obj() : s("text")
{
std::printf("%p\n", s.c_str());
}
std::string getText() { return s; }
std::string s;
};
int main()
{
Obj* pObj = new Obj();
std::string s1(pObj->getText());
std::string s2 = pObj->getText();
delete pObj;
std::printf("%p\n", s1.c_str());
std::printf("%p\n", s2.c_str());
}
Run Code Online (Sandbox Code Playgroud)
结果:
0x600022888
0x600022888
0x600022888
Run Code Online (Sandbox Code Playgroud)
Lig*_*ica 10
这将创建字符串对象的第二个实例,但现在两个字符串对象都指向堆上的相同char缓冲区.
不,他们没有.
std::string拥有他们的内容.复制a时std::string,复制其缓冲区.
我想很多人都认为,因为字符串是按值返回的,所以不需要关心Foo中原始字符串的生命周期.
那些人是对的.没有"分享".
你的价值回报很好,你不需要考虑更多.
我想在@ LightnessRacesInOrbit的答案中添加一些要点:
永远不要按值返回字符串?
永远不要string通过引用或指针返回本地.实际上,永远不要通过引用或指针返回任何本地内容.按价值就好了.
如果保证原始字符串的生命周期,只按值返回字符串?
再一次,你在倒退.如果保证原件的使用寿命,则仅通过引用或指针返回.
总是复制一下这个字符串?return std :: string(retval.c_str());
如果C++无法移出字符串(RVO/NRVO),C++会自动为您执行此操作.无需手动复制.
与getText()的调用者签订合同?
无论如何你都不需要副本
我想很多人都认为,因为字符串是按值返回的,所以不需要关心Foo中原始字符串的生命周期.这个问题与字符串没有严格的关系,但实际上适用于任何具有封装指针的类,这些指针在销毁时是免费的.
他们的假设是正确的.任何具有(工作)复制构造函数的类都可以根据需要进行复制,并且每个复制的实例都完全独立于其他类.复制构造函数负责复制堆空间.
| 归档时间: |
|
| 查看次数: |
1639 次 |
| 最近记录: |