C++:从堆栈内存返回std :: string引用

Mar*_*aux 10 c++ memory-management reference

我将首先说我已经阅读了这个主题:C++返回引用/堆栈内存.但在那里,问题是std::vector<int>作为对象类型.但我虽然行为std::string不同.这个类是不是特别为使用字符串而不必担心内存泄漏和错误的内存使用?

所以,我已经知道这是错的:

std::vector<t> &function()
{
    vector<t> v;
    return v;
}
Run Code Online (Sandbox Code Playgroud)

但这也错了吗?

std::string &function()
{
    string s = "Faz";
    s += "Far";
    s += "Boo";
    return s;
}
Run Code Online (Sandbox Code Playgroud)

谢谢


额外的问题(编辑):所以,我是正确的,当我说回(按价值计算)std::string不复制的字符序列,只有一个指向char *数组和t_size用于长度是多少?

如果这个语句是正确的,这是创建字符串深层副本的有效方法(避免替换会改变字符串)吗?

string orig = "Baz";
string copy = string(orig);
Run Code Online (Sandbox Code Playgroud)

Jam*_*lis 28

这种类型无关紧要; 对于任何对象类型,此模式始终完全,100%错误T:

T& f() {
    T x;
    return x;
}   // x is destroyed here and the returned reference is thus unusable
Run Code Online (Sandbox Code Playgroud)

如果从函数返回引用,则必须确保函数返回后它所引用的对象仍然存在.由于具有自动存储持续时间的对象在声明它们的块的末尾被销毁,因此保证在函数返回后存在它们.


Bli*_*ndy 24

你真的很接近使这些功能工作:

std::string function()
{
    string s = "Faz";
    s += "Far";
    s += "Boo";
    return s;
}
Run Code Online (Sandbox Code Playgroud)

只需让它们返回副本而不是引用即可.这就是你想要的,基于堆栈的字符串的副本.

它也会变得更好,因为返回值优化(RVO)只会创建一次字符串并返回它,就像你在堆上创建它并返回它的引用一样,都在幕后!

  • @Martijn,再次,绝对没有涉及任何类型的复制,无论是指针,引用还是本机类型(在您的示例中为`size_t`).没有任何.这就是重点,为了避免因性能原因而进行任何复制. (3认同)

R. *_*des 7

不返回引用,按值返回:

std::string function() // no ref
{
    string s = "Faz";
    s += "Far";
    s += "Boo";
    return s;
}
Run Code Online (Sandbox Code Playgroud)

如果您的编译器可以执行命名返回值优化,也就是NRVO(很可能),它会将其转换为大致相当于以下内容的内容,从而避免任何无关的副本:

// Turn the return value into an output parameter:
void function(std::string& s)
{
    s = "Faz";
    s += "Far";
    s += "Boo";
}

// ... and at the callsite,
// instead of:
std::string x = function();
// It does this something equivalent to this:
std::string x; // allocates x in the caller's stack frame
function(x); // passes x by reference
Run Code Online (Sandbox Code Playgroud)

关于额外的问题:

字符串的复制构造函数始终执行深层复制.因此,如果涉及副本,则不存在别名问题.但是,如上所述,当使用NRVO按值返回时,不会制作副本.

您可以使用几种不同的语法制作副本:

string orig = "Baz";
string copy1 = string(orig);
string copy2(orig);
string copy3 = orig;
Run Code Online (Sandbox Code Playgroud)

第二个和第三个没有语义差异:它们都只是初始化.第一个通过显式调用复制构造函数创建临时,然后使用副本初始化变量.但是编译器可以在这里复制省略(并且它很可能会复制)并且只能复制一份.