Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么C++;是否需要用户提供的默认构造函数来默认构造常量对象? C++标准(第8.5节):_C++ - Fatal编程技术网

为什么C++;是否需要用户提供的默认构造函数来默认构造常量对象? C++标准(第8.5节):

为什么C++;是否需要用户提供的默认构造函数来默认构造常量对象? C++标准(第8.5节):,c++,C++,如果程序调用const限定类型T的对象的默认初始化,则T应为具有用户提供的默认构造函数的类类型 为什么??我想不出为什么在这种情况下需要用户提供的构造函数 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;//

如果程序调用const限定类型T的对象的默认初始化,则T应为具有用户提供的默认构造函数的类类型

为什么??我想不出为什么在这种情况下需要用户提供的构造函数

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

对我纯粹的推测,但也认为其他类型也有类似的限制:

int main()
{
    const int i; // invalid
}
因此,这条规则不仅是一致的,而且(递归地)防止了单位化的
const
(sub)对象:


至于问题的另一方面(允许它用于具有默认构造函数的类型),我认为这样的想法是,具有用户提供的默认构造函数的类型在构造之后应该始终处于某种合理的状态。请注意,规则允许以下内容:

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 a.i

然后,也许我们可以制定一个规则,比如“必须在用户提供的默认构造函数中合理地初始化至少一个成员”,但这会花费太多的时间来保护Murphy。C++往往在某些点上信任程序员。

< P>原因是如果类没有用户定义的构造函数,那么它可以是POD,而POD类默认是不初始化的。所以,如果您声明一个未初始化的POD常量对象,它有什么用途?所以我认为标准执行了这个规则,所以这个对象实际上是有用的

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!
但是如果你把这个类变成非吊舱:

struct nonPOD_A
{
    nonPOD_A() {} //this makes non-POD
};

nonPOD_A a1; //initialized 
const nonPOD_A a2; //initialized 
注意吊舱和非吊舱之间的区别

用户定义的构造函数是使类非POD的一种方法。有几种方法可以做到这一点

struct nonPOD_B
{
    virtual void f() {} //virtual function make it non-POD
};

nonPOD_B b1; //initialized 
const nonPOD_B b2; //initialized 
注意,nonPOD_B没有定义用户定义的构造函数。编译它。它将汇编:

并对虚函数进行注释,然后按预期给出错误:


嗯,我想,你误解了这段话。它首先说(§8.5/9):

如果没有为对象指定初始值设定项,并且该对象是(可能是cv限定的)非POD类类型(或其数组),则该对象应默认初始化;[……]

它讨论了非POD类,可能是cv限定类型。也就是说,如果没有指定初始值设定项,则非POD对象应默认初始化。什么是默认初始化?对于非POD,规范规定(§8.5/5)

默认初始化T类型的对象意味着:
-如果T是非POD类类型(第9条),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的)

它只是讨论T的默认构造函数,不管它是用户定义的还是编译器生成的都是无关的

如果您清楚这一点,那么请理解规范接下来的内容(§8.5/9)

[…];如果对象是const限定类型,则基础类类型应具有用户声明的默认构造函数

因此,本文暗示,如果对象是const-qualified-POD类型,并且没有指定初始值设定项(因为POD不是默认初始化的),则程序将是格式错误的


顺便说一句,因为它不是POD,并且可以默认初始化。

恭喜你,你发明了一种情况,在这种情况下,
const
声明不需要任何用户定义的构造函数,也没有初始值设定项

现在,你能想出一个合理的重新措辞的规则,涵盖你的案件,但仍然使案件,应该是非法的非法?它是否少于5或6段?它是否容易和明显的应该如何应用于任何情况

我认为,制定一个规则,让您创建的声明有意义是非常困难的,并且确保该规则能够在人们阅读代码时以一种有意义的方式应用是更加困难的。我更喜欢一个在大多数情况下是正确的有点限制的规则,而不是一个非常微妙和复杂的规则它很难理解和应用


问题是,是否有令人信服的理由使规则变得更复杂?是否有一些代码很难编写或理解,如果规则更复杂,可以编写得更简单?

这被认为是一个缺陷(与标准的所有版本相比)标准的新措辞在

如果 T的默认初始化将调用用户提供的构造函数 T的(不是从基类继承的)或

  • T的每个直接非变量非静态数据成员M都有一个默认的成员初始值设定项,如果M是类类型X(或其数组),则为X const default是可构造的
  • 如果T是至少有一个非静态数据成员的联合,则正好有一个变量成员具有默认的成员初始值设定项
  • 如果T不是联合,则对于至少有一个非静态数据成员(如果有)的每个匿名联合成员,正好有一个非静态数据 成员具有默认的成员初始值设定项,并且
  • T的每个可能构造的基类都是常量默认可构造的

如果程序调用 常量限定类型T,T应为常量默认可构造类 其类型或数组

这个措辞本质上意味着显而易见的代码是有效的。如果你初始化了所有的基和成员,你可以说
A const A;
,不管你如何拼写构造函数

struct A {
};
A const a;

自从4.6.0以来,GCC已经接受了这一点。VisualStudio也接受了这一点(至少2017,不确定是否更早)。

< P>我在C++会议2018上看到了Timul-Dou勒的谈话,我终于意识到为什么标准要求用户提供的构造函数在这里,而不仅仅是用户声明的构造函数。
POD p1; //uninitialized - can be useful - hence allowed
const POD p2; //uninitialized - never useful  - hence not allowed - error
struct A {
};
A const a;
struct A {
    int x;
    A() = default;
};
struct B {
    int x;
    B() {}
};