为什么C ++需要用户提供的默认构造函数来默认构build一个const对象?
C ++标准(8.5节)说:
如果一个程序调用一个const限定typesT的对象的默认初始化,T应该是一个具有用户提供的默认构造函数的类types。
为什么? 在这种情况下,我不能想到为什么需要用户提供的构造函数。
struct B{ B():x(42){} int doSomeStuff() const{return x;} int x; }; struct A{ A(){}//other than "because the standard says so", why is this line required? B b;//not required for this example, just to illustrate //how this situation isn't totally useless }; int main(){ const A a; }
原因是如果这个类没有用户定义的构造函数,那么它可以是POD,并且POD类是默认不初始化的。 所以如果你声明一个未初始化的POD的const对象,它有什么用处呢? 所以我认为标准强制执行这个规则,以便该对象实际上是有用的。
struct POD { int i; }; POD p1; //uninitialized - but don't worry we can assign some value later on! p1.i = 10; //assign some value later on! POD p2 = POD(); //initialized const POD p3 = POD(); //initialized const POD p4; //uninitialized - error - as we cannot change it later on!
但是如果你让课堂成为非POD:
struct nonPOD_A { nonPOD_A() {} //this makes non-POD }; nonPOD_A a1; //initialized const nonPOD_A a2; //initialized
请注意POD和非POD之间的差异。
用户定义的构造函数是使类非POD的一种方法。 有几种方法可以做到这一点。
struct nonPOD_B { virtual void f() {} //virtual function make it non-POD }; nonPOD_B b1; //initialized const nonPOD_B b2; //initialized
注意nonPOD_B没有定义用户定义的构造函数。 编译它。 它会编译:
并评论虚拟function,然后给出错误,如预期的那样:
好吧,我想,你误解了这段话。 首先说这个(§8.5/ 9):
如果没有为对象指定初始化程序,并且对象是(可能是cv-qualified) 非POD类types(或其数组),则该对象应该被默认初始化; […]
它谈到了非POD类可能是cv-qualifiedtypes。 也就是说,如果没有指定初始值,那么非POD对象应该被默认初始化。 什么是默认初始化 ? 对于非POD,规范说(§8.5/ 5),
默认初始化Ttypes的对象意味着:
– 如果T是非POD类types(第9章),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化不合格)。
它只是谈论T的默认构造函数 ,不pipe它的用户定义还是编译器生成都是不相关的。
如果你清楚这一点,然后明白规范接下来说什么((§8.5/ 9),
[…] 如果对象是const限定types的,则底层类types应该有一个用户声明的默认构造函数。
因此,本文暗示, 如果对象是const限定的 PODtypes,并且没有指定初始值(因为POD没有默认初始化),那么程序将是不合格的:
POD p1; //uninitialized - can be useful - hence allowed const POD p2; //uninitialized - never useful - hence not allowed - error
顺便说一下, 这个编译好 ,因为它的非POD,并可以默认初始化 。
纯粹的猜测,但我认为其他types也有类似的限制:
int main() { const int i; // invalid }
所以,不仅这个规则是一致的,而且它(recursion地)也会阻止单位化的const
(sub)对象:
struct X { int j; }; struct A { int i; X x; } int main() { const A a; // ai and axj in unitialized states! }
至于问题的另一方面(允许它与具有默认构造函数的types),我认为这个想法是,一个用户提供的默认构造函数的types应该总是处于一个合理的状态,在施工后。 请注意,规则,因为它们允许以下内容:
struct A { explicit A(int i): initialized(true), i(i) {} // valued constructor A(): initialized(false) {} bool initialized; int i; }; const A a; // class invariant set up for the object // yet we didn't pay the cost of initializing ai
那么也许我们可以制定一个规则,例如“至less一个成员必须在用户提供的默认构造函数中进行明智的初始化”,但这样花费太多的时间来防止墨菲。 C ++在某些方面倾向于相信程序员。
恭喜,你已经发明了一个不需要用const
定义构造const
的例子,而没有初始化就没有意义。
现在您能否提出一个涵盖您的案例的合理的重新措词,但是仍然会使这些案件违法违法? 它less于5或6段? 在任何情况下如何应用它是否容易和明显?
我想提出一个规则,允许你创build的声明是有道理的,并且确保规则可以在阅读代码更困难的时候以对人有意义的方式来应用。 我宁愿有一个有些限制性的规则,在大多数情况下,这是一个很难理解和应用的细微而复杂的规则。
问题是,这个规则应该更复杂吗? 是否有一些代码难以编写或理解,如果规则更复杂,可以写得更简单?