我们假设我们有以下代码片段:
void foo(std::unique_ptr<Data> p1, std::unique_ptr<Data> p2){
bar(p1);
bar(p2);
}
int main(){
foo( std::unique_ptr<Data>{new Data}, std::unique_ptr<Data>{new Data});
}
问题是:运行此代码后是否会释放内存(无论发生什么情况)?
标准说我们不能依赖语句的顺序是函数参数,但是内部函数调用/内存分配等呢?这在这里是否很重要?
答案 0 :(得分:7)
运行此代码后,将永远释放内存(无论发生什么情况)?
在C ++之前17 :没有。一个可能的执行顺序是:
new Data
new Data
unique_ptr
构造函数unique_ptr
构造函数如果(1)抛出,我们没事。如果(2)抛出,我们还没有实际运行unique_ptr
构造函数,所以我们没有任何清理机制来从(1)中释放内存。那会泄漏。只有在(1)和(2)抛出都没有的情况下,我们才会好。
这就是标准引入std::make_unique
:
foo( std::make_unique<Data>(), std::make_unique<Data>() );
没有这个问题 - new
现在内部分组到unique_ptr
构造函数。因此,如果一个人成功,那么它已经被包裹在其RAII后卫中。
C ++ 17之后:是的。虽然函数参数的评估顺序仍未指定,但是有一个新规则,即此类评估不能交错。也就是说,给定f(g(a), h(b))
,潜在的评估顺序为:[f, g, a, h, b]
和[f, h, b, g, a]
。我们无法再在a
或b
之前评估g
和h
,这是原始代码的潜在问题。