c++ 11 允许类内定义时直接初始化非静态成员变量的几点疑惑

时间:2022-03-15 19:52:25
这样是不是说明在类的定义时就分配内存?

class BASE {

public:
     int *i = new int(5);  //ok
     BASE base;   //error   因为会引起递归定义
     BASE *base_0 = new BASE();     //error  如何理解?
     static const BASE base_1;      //ok 因为在全局区分配
     static BASE base_2;      //ok  因为在全局区分配
    ~BASE() {
     cout << "~";
    }

};


BASE *base_0 = new BASE(); //这句错误?      如何理解?   和内存分配时间有关系?  还是说和构造函数时机?  

14 个解决方案

#1


你类都没定义完,编译器怎么知道你类的大小?不知道大小那该分配多少内存?
跟你第一个error是一个意思!

你可以定义一个指针,因为只需要分配一个指针的空间而已,并不涉及到计算和分配内存

#2


递归申请内存,机器boom

#3


这条语句在运行时会陷入无穷递归,无穷尽地构造BASE。
至于为什么会在编译时报错,是因为标准有明确的规定(N4606/class.mem/Paragraph 8):
引用
... A brace-or-equal-initializer for a non-static data member specifies a default member initializer for the member,  and shall not directly or indirectly cause the implicit definition of a defaulted default constructor for the enclosing class or the exception specification of that constructor.

#4


new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

#5


引用 4 楼 ri_aje 的回复:
new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

在这里BASE被认为是完整类型。参见N4606/class.mem/Paragraph 6:
引用
... Within the class member-specification, the class is regarded as complete within function bodies,
default arguments, exception-specifications, and default member initializers (including such things in nested
classes). ... 

比如

class A {
    A() : p(nullptr) {}
    A *p = new A;  // 可以通过编译
};

#6


在定义时初始化只是方便写代码,编译器会把初始化转移到构造函数。而即便是在构造函数里这样去new,也会导致递归构造,跟是否在定义时直接初始化没必要联系。

#7


引用 1 楼 幻夢之葉的回复:
你类都没定义完,编译器怎么知道你类的大小?不知道大小那该分配多少内存?
跟你第一个error是一个意思!

你可以定义一个指针,因为只需要分配一个指针的空间而已,并不涉及到计算和分配内存

我是定义BASE类型指针呀,也就是说会知道将来如果实例化需要四个字节,我只是定义,没有在程序中任何实例化,编译也出错,如果实例化,肯定会出错,这个因为递归,可是单纯定义也不能编译通过?

#8


引用 2 楼 Saingel的回复:
递归申请内存,机器boom

没有实例化,只是定义这样的一个类

#9


引用 4 楼 ri_aje的回复:
new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

哦哦,new在此处已经要求类型完整了呀,有这样考虑过,没敢太确定。然后还有就是发现如果此处显示定义构造函数,编译可以正常通过(gcc编译),当然实例化肯定会由于递归而出错,此处不关心这个。所以构造函数和成员变量的时机具体是? new这里应该是不会分配内存,只是告诉编译器需要4个字节空间,那要求类型完整的原因或者目的是?

#10


先声明个默认构造函数就行了.

class BASE {
 
public:
BASE();
     int *i = new int(5);  //ok
     //BASE base;   //error   因为会引起递归定义
     BASE *base_0 = new BASE();     //error  如何理解?
     static const BASE base_1;      //ok 因为在全局区分配
     static BASE base_2;      //ok  因为在全局区分配
    ~BASE() {
    }
};

#11


引用 9 楼 QuantumEnergy 的回复:
Quote: 引用 4 楼 ri_aje的回复:
new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

哦哦,new在此处已经要求类型完整了呀,有这样考虑过,没敢太确定。然后还有就是发现如果此处显示定义构造函数,编译可以正常通过(gcc编译),当然实例化肯定会由于递归而出错,此处不关心这个。所以构造函数和成员变量的时机具体是? new这里应该是不会分配内存,只是告诉编译器需要4个字节空间,那要求类型完整的原因或者目的是?

指针不会递归出错啊。

#12


就样就递归申请了..

#13


引用 5 楼 xsklld 的回复:
Quote: 引用 4 楼 ri_aje 的回复:

new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

在这里BASE被认为是完整类型。参见N4606/class.mem/Paragraph 6:
引用
... Within the class member-specification, the class is regarded as complete within function bodies,
default arguments, exception-specifications, and default member initializers (including such things in nested
classes). ... 

比如

class A {
    A() : p(nullptr) {}
    A *p = new A;  // 可以通过编译
};

嗯,你说的对,我疏忽了。default member init 是新加的,我以为没有特权呢。主楼的错误是因为缺默认构造函数。

#14


引用 9 楼 QuantumEnergy 的回复:
Quote: 引用 4 楼 ri_aje的回复:
new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

哦哦,new在此处已经要求类型完整了呀,有这样考虑过,没敢太确定。然后还有就是发现如果此处显示定义构造函数,编译可以正常通过(gcc编译),当然实例化肯定会由于递归而出错,此处不关心这个。所以构造函数和成员变量的时机具体是? new这里应该是不会分配内存,只是告诉编译器需要4个字节空间,那要求类型完整的原因或者目的是?

4 楼我说错了,new BASE 的时候 BASE 视同完整的,标准特许的。
不过这里要求一个你自己写的默认构造函数,否则 new BASE 的时候要调用默认构造函数,后者继续调用 new BASE,造成死循环了。

#1


你类都没定义完,编译器怎么知道你类的大小?不知道大小那该分配多少内存?
跟你第一个error是一个意思!

你可以定义一个指针,因为只需要分配一个指针的空间而已,并不涉及到计算和分配内存

#2


递归申请内存,机器boom

#3


这条语句在运行时会陷入无穷递归,无穷尽地构造BASE。
至于为什么会在编译时报错,是因为标准有明确的规定(N4606/class.mem/Paragraph 8):
引用
... A brace-or-equal-initializer for a non-static data member specifies a default member initializer for the member,  and shall not directly or indirectly cause the implicit definition of a defaulted default constructor for the enclosing class or the exception specification of that constructor.

#4


new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

#5


引用 4 楼 ri_aje 的回复:
new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

在这里BASE被认为是完整类型。参见N4606/class.mem/Paragraph 6:
引用
... Within the class member-specification, the class is regarded as complete within function bodies,
default arguments, exception-specifications, and default member initializers (including such things in nested
classes). ... 

比如

class A {
    A() : p(nullptr) {}
    A *p = new A;  // 可以通过编译
};

#6


在定义时初始化只是方便写代码,编译器会把初始化转移到构造函数。而即便是在构造函数里这样去new,也会导致递归构造,跟是否在定义时直接初始化没必要联系。

#7


引用 1 楼 幻夢之葉的回复:
你类都没定义完,编译器怎么知道你类的大小?不知道大小那该分配多少内存?
跟你第一个error是一个意思!

你可以定义一个指针,因为只需要分配一个指针的空间而已,并不涉及到计算和分配内存

我是定义BASE类型指针呀,也就是说会知道将来如果实例化需要四个字节,我只是定义,没有在程序中任何实例化,编译也出错,如果实例化,肯定会出错,这个因为递归,可是单纯定义也不能编译通过?

#8


引用 2 楼 Saingel的回复:
递归申请内存,机器boom

没有实例化,只是定义这样的一个类

#9


引用 4 楼 ri_aje的回复:
new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

哦哦,new在此处已经要求类型完整了呀,有这样考虑过,没敢太确定。然后还有就是发现如果此处显示定义构造函数,编译可以正常通过(gcc编译),当然实例化肯定会由于递归而出错,此处不关心这个。所以构造函数和成员变量的时机具体是? new这里应该是不会分配内存,只是告诉编译器需要4个字节空间,那要求类型完整的原因或者目的是?

#10


先声明个默认构造函数就行了.

class BASE {
 
public:
BASE();
     int *i = new int(5);  //ok
     //BASE base;   //error   因为会引起递归定义
     BASE *base_0 = new BASE();     //error  如何理解?
     static const BASE base_1;      //ok 因为在全局区分配
     static BASE base_2;      //ok  因为在全局区分配
    ~BASE() {
    }
};

#11


引用 9 楼 QuantumEnergy 的回复:
Quote: 引用 4 楼 ri_aje的回复:
new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

哦哦,new在此处已经要求类型完整了呀,有这样考虑过,没敢太确定。然后还有就是发现如果此处显示定义构造函数,编译可以正常通过(gcc编译),当然实例化肯定会由于递归而出错,此处不关心这个。所以构造函数和成员变量的时机具体是? new这里应该是不会分配内存,只是告诉编译器需要4个字节空间,那要求类型完整的原因或者目的是?

指针不会递归出错啊。

#12


就样就递归申请了..

#13


引用 5 楼 xsklld 的回复:
Quote: 引用 4 楼 ri_aje 的回复:

new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

在这里BASE被认为是完整类型。参见N4606/class.mem/Paragraph 6:
引用
... Within the class member-specification, the class is regarded as complete within function bodies,
default arguments, exception-specifications, and default member initializers (including such things in nested
classes). ... 

比如

class A {
    A() : p(nullptr) {}
    A *p = new A;  // 可以通过编译
};

嗯,你说的对,我疏忽了。default member init 是新加的,我以为没有特权呢。主楼的错误是因为缺默认构造函数。

#14


引用 9 楼 QuantumEnergy 的回复:
Quote: 引用 4 楼 ri_aje的回复:
new int 那句初始化最终变成所有构造函数的一部分,除非该构造函数的 member init list 里面明确对 int i 初始化了,这时构造函数的初始化优先。
new 操作符要完整类型,BASE 在 BASE 里面的时候还是不完整类型呢,所以出错。

哦哦,new在此处已经要求类型完整了呀,有这样考虑过,没敢太确定。然后还有就是发现如果此处显示定义构造函数,编译可以正常通过(gcc编译),当然实例化肯定会由于递归而出错,此处不关心这个。所以构造函数和成员变量的时机具体是? new这里应该是不会分配内存,只是告诉编译器需要4个字节空间,那要求类型完整的原因或者目的是?

4 楼我说错了,new BASE 的时候 BASE 视同完整的,标准特许的。
不过这里要求一个你自己写的默认构造函数,否则 new BASE 的时候要调用默认构造函数,后者继续调用 new BASE,造成死循环了。