问题描述
struct B {
B() throw();
B(const B&) = default; // implicit exception specification is noexcept(true)
B(B&&,int = (throw Y(),0)) noexcept;
~B() noexcept(false);
};
int n = 7;
struct D : public A,public B {
int * p = new int[n];
// D::D() potentially-throwing,as the new operator may throw bad_alloc or bad_array_new_length
// D::D(const D&) non-throwing
// D::D(D&&) potentially-throwing,as the default argument for B's constructor may throw
// D:: D() potentially-throwing
};
请考虑以上从except.spec#11引用的代码。除了D::D(D&&)
之外,我对D的所有构造函数的异常规范都毫无疑问,它遵循以下规则:
对于X类的隐式声明的构造函数,或者在第一个声明中没有默认值的没有noexcept-specifier的构造函数,当且仅当以下任何一种构造可能被抛出时,才具有潜在抛出的异常规范:
很显然,使D::D(D&&)
具有可能抛出的异常规范的规则既不是第一个项目符号,也不是第三个项目符号。对于第一条规则,用于初始化类型B
的基础子对象的选定构造函数是B(B&&,0)) noexcept
,它声明为具有非抛出异常规范。第三个规则是默认构造函数。因此,只有第二条规则适用于这种情况。
但是,D::D(D&&)
不应具有可能抛出的异常规范,除非表达式throw Y()
被视为D::D(D&&)
的子表达式。
定义立即子表达式的规则如下:
表达式e的直接子表达式为
表达式e的子表达式是e的直接子表达式或e的直接子表达式的子表达式。
了解子表达式规则的简单方法是它可以递归工作,即
immediate subexpression of immediate subexpression... of immediate subexpression of e
是e
的子表达式。
由于第四个项目符号,我同意表达式throw Y()
是函数B(B&&,0)) noexcept
的子表达式。但是,我不知道B(B&&,0)) noexcept
是否被视为由表达式D::D(D&&)
调用的隐式调用函数,该表达式似乎服从第二个项目符号。如果是这样,请考虑以下代码:
class Test{
test(){}
~test(){}
};
void func(){
Test t{} // implicitly invoke the defautl constructor of `Test`
// would implicitly invoke the destructor of `Test`
}
int main(){
func();
}
因此,正如我在评论中所写,Test
的构造函数和析构函数是否被视为表达式func()
的子表达式?如果不是,如何解释措词a subexpression of such an initialization
?所以,我的问题是:
第一季度:
在第二个示例中,隐式调用的构造函数或析构函数是否被视为表达式func()
的子表达式?
第二季度:
如果第一个问题的答案为否,那么如何解释a subexpression of such an initialization
?
解决方法
对于第一个规则,用于初始化类型to setup
let mylist1 [1 2 3]
let mylist2 [4 5 6]
set mylist1 sentence mylist1 mylist2
show mylist1
end
的基本子对象的选定构造函数是B
,该声明的构造函数具有非抛出异常规范。这意味着B (B&&,int = (throw Y(),0)) noexcept
的构造函数在被调用时不会抛出。但是,在B
调用D
之前,它必须根据其默认值生成第二个参数,该参数将抛出第二个参数。因此,B
的抛出不是因为D
而是因为默认参数,它是在B
之外执行的。
为了查看初始化的子表达式是什么,您需要考虑由编译器生成的代码。您对B
的调用不会在该调用的范围内构造类型为func()
的对象,因为编译器不会将任何对象注入T
的范围内。该对象是在main
范围内构造的,不计入。