在这里尝试更多地理解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();
答案 0 :(得分:3)
在问题1中,是的,当函数dummy
结束时,将释放变量s
的内存,因为这是s
变量的封闭范围。
在问题2中,编译器可能会使用return value optimization来避免将内存从s1
复制到s
,因为 $scope.gridOptions.onRegisterApi = function(gridApi){
//set gridApi on scope
$scope.gridApi = gridApi;
gridApi.selection.on.rowSelectionChanged($scope,function(row){
var msg = 'row selected ' + row.isSelected;
$log.log(msg);
});
gridApi.selection.on.rowSelectionChangedBatch($scope,function(rows){
var msg = 'rows changed ' + rows.length;
$log.log(msg);
});
};
即将超出范围
答案 1 :(得分:3)
问题1:在下面的代码片段中,编译器是否足够聪明以在函数末尾释放用户数据(在堆中,由s隐式指向)?
是的,它是必需的。在函数作用域的末尾,将调用字符串的析构函数,这将释放分配的内存。
对象s
被称为具有“自动存储持续时间”,并且标准通过§3.7.3/ 1描述:
显式声明寄存器或未显式声明为static或extern的块范围变量具有自动存储持续时间。这些实体的存储将持续到创建它们的块退出。
问题2:在下面的代码片段中,编译器在函数返回时不会释放s指向的用户数据。是对的吗?如果是这样,编译器可以在调用者中释放用户数据(如果调用者函数本身不返回字符串对象)。
编译器可以使用所谓的RVO(返回值优化)来删除副本。具体而言,标准词语如下,§12.8/ 31:
在下列情况下(可以合并以消除多份副本),允许复制/移动操作(称为复制省略)的省略:
- 在具有类返回类型的函数的return语句中,当表达式是具有与函数相同的cv-非限定类型的非易失性自动对象(函数或catch子句参数除外)的名称时通过将自动对象直接构造到函数的返回值
中,可以省略复制/移动操作- 在throw-expression(5.17)中,当操作数是非易失性自动对象(函数或catch子句参数除外)的名称时,其范围不会超出最内层封闭的末尾 - 块(如果有的话),通过将自动对象直接构造到异常对象中,可以省略从操作数到异常对象(15.1)的复制/移动操作
- 当一个未绑定到引用(12.2)的临时类对象被复制/移动到具有相同cv-nonqualified类型的类对象时,可以通过直接构造临时对象来省略复制/移动操作进入省略的复制/移动的目标
- 当异常处理程序的异常声明(第15条)声明一个相同类型的对象(cv-qualification除外)作为异常对象(15.1)时,可以通过处理异常声明来省略复制操作如果除了为exception-declaration声明的对象执行构造函数和析构函数之外,程序的含义将保持不变,则作为异常对象的别名。 [注意:不能从异常对象移动,因为它始终是左值。 -endnote]