谁管理参数中的复制构造函数抛出的异常?

Who manages the exception thrown by a copy constructor in parameters?

假设我有这个功能

void foo() noexcept
{
   // Safely noexcept code.
}

然后这个 class:

class Bar
{
   Bar(const Bar&) { ... } // Is not noexcept, so might throw
   // Non movable:
   Bar(Bar&&) = delete;
};

现在,我需要修改 foo() 以按值接收 Bar:

void foo(Bar bar) // noexcept?
{
   // Safely noexcept code
}

我假设 Bar 的复制是在调用 foo 之前完成的,所以 foo 的代码理论上仍然可以是 noexcept, 但我不确定在 C++ 级别是如何定义的。 foo 是否需要删除 noexcept 或在处理 Bar 时可能抛出的调用者? 它取决于调用模式(stdcall、farcall 等)或编译器吗? 更新:在其他问题中,我没有找到任何对调用约定的引用。这应该对行为产生影响。我想。

参见 [expr.call]/4:

The initialization and destruction of each parameter occurs within the context of the calling function. [ Example: The access of the constructor, conversion functions or destructor is checked at the point of call in the calling function. If a constructor or destructor for a function parameter throws an exception, the search for a handler starts in the scope of the calling function; in particular, if the function called has a function-try-block (Clause 18) with a handler that could handle the exception, this handler is not considered. —end example ]

因此您仍然可以标记 foo noexcept,即使 bar 的初始化可能会抛出。调用函数不应该是noexcept。 (也就是说,除非您同意在出现异常时终止程序。)

参数的构造发生在调用者中;一旦所有参数都已 built/converted 函数被调用。

可能不明显的一点是,在 C++ 中,即使是未传递参数的默认值表达式也会发生在调用者中:即

void foo(MyClass x=MyClass()) {
    ...
}

情况下的构造
foo();

仍然在调用方站点完成,在实际调用函数之前。