假设我有类型T
和U
,以及函数U f(T)
和T g()
,我编写了表达式f(g())
。在什么情况下,附近未序列表达式中的代码可能会在g
之后但f
之前执行?
我理解一个情况是在h(f(g()), j())
之类的函数调用中,j
可以在g
和f
的任何时间执行。这本质上是唯一的示例,还是其他的?
为了激励,函数std::make_shared<T>
和std::make_unique<T>
可用于编写更多异常安全的代码,如http://herbsutter.com/gotw/_102/中此不安全代码示例所示:
// In some header file:
void f( std::unique_ptr<T1>, std::unique_ptr<T2> );
// At some call site:
f( std::unique_ptr<T1>{ new T1 }, std::unique_ptr<T2>{ new T2 } );
T2
构造函数可能会在T1
构造函数之后但在std::unique_ptr<T1>
构造函数之前抛出异常,从而导致T1
泄露。解决方案是改为编写f( make_unique<T1>(), make_unique<T2>() );
。
我发现std::unique_ptr
提供的异常安全性的每次讨论都使用相同的示例。这让我想知道多参数函数中的参数表达式(包括某些运算符,如+
和[]
)是否是预期此行为的唯一情况。
答案 0 :(得分:5)
[intro.execution]
(§1.9)包含规则,实际上非常简单。
14在每个值计算和与下一个要评估的完整表达式相关的副作用之前,每个与全表达式相关的值计算和副作用都会被排序。
15除非另有说明,否则对单个算子的操作数和个别表达式的子表达式的评估是不合理的。
完整表达式就是它所说的:一个表达式,它不是任何其他表达式的子表达式。因此,只有表达式的子表达式才能被排除,而不是全部。例如,某些运算符对其参数的执行进行排序,并且函数调用是不确定的顺序(即,不是交错的)。