You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++默认初始化、值初始化与类内初始化行为异常问题咨询

你可能觉得代码很长我写了很多内容,但相信我它其实非常简单。

代码

#include <iostream>

class A
        {
        public:
            int k1=3;
            float f1=34.20;
            char ch1='a';
            std::string str1="bonaparte";

            void display()
            {
                std::cout<<k1<<" "<<f1<<" "<<ch1<<" "<<str1<<" xx\n";
            }

        };

class B
{
    public:
        int k2;
        float f2;
        char ch2;
        std::string str2;

        void display()
        {
            std::cout<<k2<<" "<<f2<<" "<<ch2<<" "<<str2<<" xx\n";
        }

};

A a1;
B b1;

A *p1=new A;
B *q1=new B;
int main()
{
    A a2, a3{};
    B b2, b3{};

    A *p2=new A;
    A *p3=new A{};
    A *p4=new A();

    B *q2=new B;
    B *q3=new B{};
    B *q4=new B();

    a1.display();
    a2.display();
    a3.display();
    p1->display();
    p2->display();
    p3->display();
    p4->display();

    std::cout<<"\n\n";

    b1.display();
    b2.display();
    b3.display();
    q1->display();
    q2->display();
    q3->display();
    q4->display();
}

运行输出

3 34.2 a bonaparte xx
3 34.2 a bonaparte xx
3 34.2 a bonaparte xx
3 34.2 a bonaparte xx
3 34.2 a bonaparte xx
3 34.2 a bonaparte xx
3 34.2 a bonaparte xx


0 0    xx
13965136 0 ╠  xx
0 0    xx
38872208 0 p  xx
38872208 0 p  xx
0 0    xx
0 0    xx

类B相关疑问

  • b1是值初始化,准确来说是零初始化。
  • b2是默认初始化,即未进行初始化。
  • b3是花括号初始化,属于值初始化,最终触发零初始化。
  • 我没办法像写q4那样写b4()(不是完全一致,你明白我的意思),因为这会被识别为函数定义而非对象声明,也就是Most vexing parse问题。
  • 我原本认为q1应该是值初始化,但输出结果和我的预期不符。
  • q2是默认初始化,即未进行初始化。
  • q3是花括号初始化,属于值初始化,最终触发零初始化。
  • q4会调用构造函数,但类没有用户定义的构造函数,所以应该是默认初始化,也就是未初始化。
  • 我知道q1、q2、q3、q4都是指针,为了表述简便我直接用上述说法,比如称q3是花括号初始化,我想你能明白我的意思。
  • 我对b1、b2、b3的认知和运行结果一致,这部分可能只是巧合,如果我的理解有误也请纠正我。
  • 我认为b1的规则也应该适用于q1,但实际结果并非如此,请解释原因。
  • q2的运行结果符合我的预期,如果我的理解有误也请纠正。
  • 现在我对q3和q4的行为存在困惑:我认为两者都会调用构造函数,但我们没有用户定义的构造函数,所以应该走默认初始化也就是不初始化,对吗?那为什么两者实际上都是值初始化,准确来说是零初始化呢?

类A相关疑问

我认为如果我们使用类内初始化,无论在哪里声明对象,都会按我们提供的值完成初始化,这个结论是否正确?也请补充说明类内初始化的相关规则。


解答

类B疑问解答

  1. 你对b1、b2、b3的认知完全正确,不是巧合:
    • b1是静态存储期的全局对象,程序启动阶段会先对所有静态存储期对象做零初始化,所以内置类型成员全为0,std::string成员默认初始化为空,符合输出结果。
    • b2是栈上的局部对象,采用默认初始化规则:对于没有用户定义默认构造函数的类,隐式生成的默认构造函数不会初始化内置类型成员,所以这些成员的值是未定义的垃圾值,和输出结果一致。
    • b3采用空花括号的列表初始化,属于值初始化范畴:对于没有用户定义默认构造函数的类,值初始化会先对整个对象做零初始化,再调用隐式默认构造函数,所以内置类型成员全为0,符合输出。
  2. b1的规则不适用于q1:q1指向的是动态存储期对象,由new B生成,不带初始化器的new T属于默认初始化,和局部对象b2规则一致,内置类型成员不会被初始化,自然是垃圾值,和静态存储期的b1零初始化规则完全独立。
  3. 你对q2的认知正确,不带初始化器的new B是默认初始化,内置成员为垃圾值。
  4. 你对q3、q4的规则理解有误:空括号()和空花括号{}的初始化都属于值初始化,不是默认初始化。对于没有用户定义默认构造函数的类,值初始化会先零初始化整个对象,再调用隐式默认构造函数,所以内置类型成员全为0,符合输出结果。只有不带任何括号/花括号的new T才是默认初始化。

类A疑问解答

你的结论基本正确。只要类内初始化(默认成员初始化器)没有被构造函数初始化列表覆盖,不管对象是全局、局部还是动态分配,不管是默认初始化还是值初始化,都会优先使用类内的初始化值。
补充类内初始化规则:

  • 仅支持非静态成员变量,C++11及以上版本标准可用
  • 构造函数初始化列表对同一成员的赋值优先级高于类内初始化
  • 普通静态成员变量不能使用类内初始化(静态constexpr成员除外)

内容的提问来源于stack exchange,提问作者Abhishek Mane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 17:45:02