关于字符串对象寿命的几个问题

Some questions on life span of a string object

本文关键字:几个问题 对象 字符串      更新时间:2023-10-16

试着在这里多理解一点c++字符串。这里的编译器是g++ 4.7.3。

问题1:在下面的代码片段中,编译器是否足够聪明,可以在函数结束时释放用户数据(在堆中,由s隐式指向)?我想答案是肯定的,只是想确认一下。

void dummy() {
    string s;
    s.append("hello");
    //more append
}

问题2:在下面的代码片段中,当函数返回时,编译器不会释放s所指向的用户数据。对吗?如果是这样,则编译器可以在调用者中释放用户数据(如果调用者函数本身不返回字符串对象)。

string dummy() {
    string s;
    s.append("hello");
    //more append
    return s;
}
//some caller
string s1 = dummy();

在问题1中,是的,当函数dummy结束时,变量s的内存将被释放,因为这是s变量的封闭作用域。

在问题2中,编译器可能会使用返回值优化来避免必须将内存从s复制到s1,因为s即将超出作用域。

问题1:在下面的代码片段中,编译器是否足够聪明,可以在函数结束时释放用户数据(在堆中,由s隐式指向)?

是的,这是必须的。在函数作用域结束时,将调用字符串的析构函数,这将释放分配的内存。

对象s被认为具有"自动存储持续时间",并且在标准中通过§3.7.3/1:

进行了描述。

块作用域变量显式声明为寄存器或未显式声明为静态或外部,具有自动存储持续时间。这些实体的存储将持续到创建它们的块退出为止。


问题2:在下面的代码片段中,当函数返回时,编译器不会释放s所指向的用户数据。对吗?如果是这样,编译器可以在调用者中释放用户数据(如果调用者函数本身不返回字符串对象)。

编译器可以使用所谓的RVO(返回值优化)来省略那里的副本。具体地说,在§12.8/31中,这是标准的词语:

这种对拷贝/移动操作的省略,称为拷贝省略,在以下情况下是允许的(可以结合使用以消除多个拷贝):

  • 在具有类返回类型的函数的返回语句中,当表达式是与函数返回类型相同的非易失性自动对象(函数或catch子句参数除外)的名称时,可以通过将自动对象直接构造为函数的返回值
  • 来省略复制/移动操作。
  • 在throw表达式(5.17)中,当操作数是非易失性自动对象(函数或catch子句参数除外)的名称,其作用域不超出最内层的封闭try块(如果有)的末尾时,可以通过将自动对象直接构造为异常对象
  • 来省略从操作数到异常对象的复制/移动操作(15.1)。
  • 当没有绑定到引用(12.2)的临时类对象被复制/移动到具有相同cv- undefined类型的类对象时,可以通过将临时对象直接构造为省略的copy/move
  • 的目标来省略复制/移动操作。
  • 当异常处理程序(第15条)的异常声明声明了一个与异常对象(15.1)相同类型的对象(cv-qualification除外)时,如果程序的意义除了为异常声明声明的对象执行构造函数和析构函数外不会改变,则可以通过将异常声明视为异常对象的别名来省略复制操作。注意:不能从异常对象移出,因为它始终是左值。尾注)