是否定义了函数参数的内部执行顺序?

Is internal order of execution in function parameters defined?

假设我们有以下代码片段:

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});
}

问题是:运行 这段代码(无论发生什么)时,内存是否总是会被释放?

标准说我们不能依赖语句的顺序作为函数参数,但是内部函数 calls/memory 分配等呢?它在这里很重要吗?

will memory always be freed upon running this code (no matter what happens) ?

C++17之前:不。一种可能的执行顺序是:

  1. 离开new Data
  2. new Data
  3. unique_ptr构造函数
  4. 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]。不再可能在 gh 之前同时计算 ab,这是原始代码的潜在问题。