C++初始化方法总结

在 C++ 中,初始化是指为变量或对象赋予初始值的过程。不同类型的实体(如基本类型、数组、类对象等)具有不同的初始化方式。本文将对 C++ 的初始化方式进行一次总结。

基础类型初始化(int, double, char 等)

默认初始化

  • a. 局部变量默认值为未定义(可能是0,也可能是任何其他内存数据);
  • b. 全局变量,静态变量默认为零值。

// 局部变量:未定义值;
// 全局变量:默认0
int a;  

// 静态变量:默认0.0   
static double b;

2.直接初始化

使用括号 () 赋值(C++98 起支持)。


int x(10);
char c('a');
double d(3.14);

3.拷贝初始化

使用等号 = 赋值(本质是调用拷贝构造函数)。


int   y = 20;
char ch = 'b';

4.列表初始化(C++11 起)

使用花括号 {} 赋值(支持防止窄化转换,更安全)。


// 正确
int m{30};
char k{'c'};    

// 错误:double 转 int 是窄化转换,编译报错
// int n{3.14};

5.值初始化

对无初始值的变量强制初始化为零(常用于动态分配)。


// z = 0
int z{};

// w = 0.0
double w{};   

// 动态分配的 int 初始化为 0
int* ptr = new int();

数组初始化

1.默认初始化

全局/静态数组默认零初始化,局部数组未初始化(值不确定)。


 // 局部:未定义;全局:全0
int arr1[5];        

// 全0
static int arr2[3];

2.列表初始化(C 风格)

用 {} 赋值,未指定的元素默认零初始化。


// 前3个为1,2,3,后2个为0
int arr3[5] = {1, 2, 3};  

// 自动推导长度为6(含'�')
char str1[] = "hello";

3.列表初始化(C++11 起,省略等号)


int arr4[3]{4, 5, 6};

// 显式添加结束符
char str2[]{'h', 'i', '�'};

4.动态数组初始化(C++11 起)

动态分配数组时支持列表初始化。


int* arr5 = new int[3]{7, 8, 9};

类与结构体初始化

1.默认构造函数初始化

若类定义了默认构造函数,可直接声明对象。


class Person 
{
public:
    // 默认构造函数
    Person() : _age(0) {}  

public:
    int _age;
};

// 调用默认构造函数,_age=0
Person p1;

2.带参数的构造函数初始化(直接初始化)


class Person 
{
public:
    // 默认构造函数
    Person() : _age(0) {}  

public:
    int _age;
};

// 直接初始化,age=20
Person p2(20);

3.拷贝初始化(调用拷贝构造函数)


// 拷贝初始化(需拷贝构造函数)
Person p3 = p2;

4.列表初始化(C++11 起,适用于聚合类或带构造函数的类)

  • a. 聚合类(无用户定义构造函数、无私有/保护成员等)可直接用列表初始化成员。

struct Point 
{
    int _x;
    int _y;
};

// x=10, y=20
Point p4{10, 20};
  • b.带构造函数的类:若构造函数支持,可通过列表传递参数。

class Person 
{
public:
    Person(int a, string n) : _age(a), _name(n) {}

public:
    int     _age;
    string _name;
};

// 等价于 Person p5(25, "Alice")
Person p5{25, "Alice"};

5.成员初始化列表(构造函数内初始化成员)

“成员初始化列表”是 C++ 中构造函数的一种特殊语法,用于在构造函数体执行之前初始化类的成员变量。其格式为在构造函数参数列表后使用冒号 : 引出,多个成员的初始化用逗号 , 分隔(例如下方示例中的 _id(i), _name(n))。
成员初始化列表具有以下好处:

  • a.效率更高:直接初始化成员变量,避免了先调用默认构造函数再赋值的过程(尤其对于没有默认构造函数的类类型成员,必须使用初始化列表)。
  • b.必要性:常量成员(const)、引用成员(&)以及没有默认构造函数的类类型成员,必须通过成员初始化列表进行初始化,无法在构造函数体内赋值。

class Student 
{
public:
    // 成员初始化列表
    Student(int i, string n) : _id(i), _name(n) {}
public:
    int     _id;
    string _name;
};

容器初始化(STL 容器,如 vector、string 等)

1.默认初始化


// 空向量
vector<int> v1;  

// 空字符串
string s1;

2.带参数初始化


// 5个元素,每个为0
vector<int> v2(5, 0);  

// "aaa"
string s2(3, 'a');

3.列表初始化(C++11 起)


 // 元素为1,2,3,4
vector<int> v3{1, 2, 3, 4}; 

// "hello"
string s3{"hello"};    

// 键值对初始化
map<int, string> m{{1, "one"}, {2, "two"}};

4.范围初始化

用其他容器的范围初始化。


// 复制v3的元素
vector<int> v4(v3.begin(), v3.end());

指针与动态内存初始化

1.空指针初始化(C++11 起推荐 nullptr)


// 空指针(优于 NULL,避免类型混淆)
int* p1 = nullptr;  

// C风格空指针(本质是0)
char* p2 = NULL;

2.指向已有变量


int x = 10;

// p3指向x
int* p3 = &x;

3.动态分配初始化(new 操作符)


// 动态分配int并初始化为100
int* p4 = new int(100);   

// 动态数组初始化(C++11起)
int* p5 = new int[3]{1, 2, 3};

引用初始化

引用必须在声明时初始化,且一旦初始化后不能更改指向。


int a = 5;

// 引用a
int& ref1 = a;       

// 常量引用可绑定字面量
const int& ref2 = 10;

C++11 后的新特性

1.{} 统一初始化

用 {} 统一各类初始化(减少歧义,支持防止窄化转换)。


int a{5};
vector<int> v{1, 2, 3};
Person p{20, "Bob"};

2.列表初始化器(initializer_list)

允许函数接收任意长度的同类型参数(如 STL 容器的构造函数)。

void Print(initializer_list<int> list) 
{
    for (auto x : list) 
    {
        cout << x << " ";
    }
}

// 调用时传递列表
Print({1, 2, 3, 4});

总结

  • 1.C++98 主要支持:默认初始化、直接初始化(使用圆括号 ())、拷贝初始化(使用赋值运算符 =)。
  • 2.C++11 新增:列表初始化(使用花括号 {})、nullptr 关键字、std::initializer_list 类型等特性,统一了初始化语法并增强了类型安全性。
  • 3.列表初始化({})是推荐的现代 C++ 编程方式,尤其适用于防止窄化转换和保持统一的代码风格。

附:参考示例


#include <initializer_list>
#include <iostream>
#include <map>
#include <string>
#include <vector>

using namespace std;

// 定义测试类(用于演示类的初始化)
class MyClass
{
public:
    // 默认构造函数
    MyClass()
        : _a(0), _b(0.0), _c("default")
    {
        cout << "调用默认构造函数" << endl;
    }

    // 带参数的构造函数
    MyClass(int a, double b, string c)
        : _a(a), _b(b), _c(c)
    {
        cout << "调用带参构造函数" << endl;
    }

    // 拷贝构造函数
    MyClass(const MyClass& other)
        : _a(other._a), _b(other._b), _c(other._c)
    {
        cout << "调用拷贝构造函数" << endl;
    }

    // 支持initializer_list的构造函数(C++11起)
    MyClass(initializer_list<int> list)
    {
        cout << "调用initializer_list构造函数" << endl;
        _a = *list.begin(); // 取列表第一个元素
        _b = 0.0;
        _c = "from list";
    }

public:
    int    _a;
    double _b;
    string _c;
};

// 聚合类(无用户定义构造函数,用于演示聚合初始化)
struct Aggregate
{
    int    _x;
    double _y;
    string _z;
};

// 测试initializer_list参数的函数(C++11起)
void PrintList(initializer_list<string> items)
{
    for (const auto& item : items)
    {
        cout << item << " ";
    }
    cout << endl;
}

int main()
{
    // 基础类型初始化
    cout << "----- 基础类型初始化 -----" << endl;

    // 1. 默认初始化(局部变量未定义,全局变量默认0)
    // 局部变量:值未定义(危险)
    int basicDefault;
    cout << "局部变量默认初始化: "
         << basicDefault
         << endl;

    // 静态变量:默认0
    static int staticDefault;
    cout << "静态默认初始化: "
         << staticDefault
         << endl;

    // 2. 直接初始化(C++98起)
    int  direct(10);
    char directChar('A');
    cout << "直接初始化: "
         << direct << ", "
         << directChar
         << endl;

    // 3. 拷贝初始化(C++98起)
    int    copy         = 20;
    double copyDouble = 3.14;
    cout << "拷贝初始化: "
         << copy << ", "
         << copyDouble
         << endl;

    // 4. 列表初始化(C++11起,防止窄化转换)
    int listInit{30};

    // 错误:窄化转换(double→int)
    // int narrow{3.14};
    cout << "列表初始化: "
         << listInit << endl;

    // 5. 值初始化(强制零初始化)
    // 等价于int valueInit = 0
    int    valueInit{};
    double valueDouble{};
    cout << "值初始化: "
         << valueInit << ", "
         << valueDouble << endl;

    // 数组初始化
    cout << "n----- 数组初始化 -----" << endl;

    // 1. 默认初始化
    // 局部数组:值未定义
    int arrDefault[3];
    cout << "局部数组默认初始化: "
         << arrDefault[0] << ","
         << arrDefault[1] << endl;

    // 静态数组:默认全0
    static int staticArr[3];
    cout << "静态数组默认初始化: "
         << staticArr[0] << ","
         << staticArr[1] << endl;

    // 2. C风格列表初始化(带等号)
    // 未指定元素默认0
    int arrCStyle[5] = {1, 2, 3};
    cout << "C 风格数组初始化: ";
    for (int i : arrCStyle)
    {
        cout << i << " ";
    }
    cout << endl;

    // 3. C++11列表初始化(省略等号)
    int arrCPP11[3]{4, 5, 6};
    cout << "C++11数组初始化: ";
    for (int i : arrCPP11)
    {
        cout << i << " ";
    }
    cout << endl;

    // 4. 动态数组初始化(C++11起支持列表)
    int* dynArr = new int[4]{7, 8, 9, 10};
    cout << "动态数组初始化: ";
    for (int i = 0; i < 4; ++i)
    {
        cout << dynArr[i] << " ";
    }
    cout << endl;
    delete[] dynArr;

    // 类与结构体初始化
    cout << "n----- 类与结构体初始化 -----" << endl;

    // 1. 类的默认构造函数初始化
    MyClass objDefault;
    cout << "默认构造: "
         << objDefault._a << ","
         << objDefault._b << endl;

    // 2. 类的直接初始化(带参构造)
    MyClass objDirect(1, 3.14, "direct");
    cout << "直接初始化: "
         << objDirect._a << ","
         << objDirect._b << endl;

    // 3. 类的拷贝初始化
    MyClass objCopy = objDirect; // 调用拷贝构造
    cout << "拷贝初始化: "
         << objCopy._a
         << ","
         << objCopy._c
         << endl;

    // 4. 类的列表初始化(匹配带参构造)
    // 等价于MyClass(2,6.28,"list")
    MyClass objList{2, 6.28, "list"};
    cout << "类列表初始化: "
         << objList._a << ","
         << objList._c << endl;

    // 5. 类的initializer_list初始化(C++11起)
    // 匹配initializer_list构造
    MyClass objInitList{100, 200, 300};
    cout << "initializer_list初始化: "
         << objInitList._a
         << endl;

    // 6. 聚合类初始化(无构造函数,直接初始化成员)
    Aggregate agg{10, 20.5, "aggregate"};
    cout << "聚合类初始化: "
         << agg._x << ","
         << agg._y << ","
         << agg._z << endl;

    // 7. 成员初始化列表(在类构造函数中,见MyClass定义)
    // STL容器初始化
    cout << "n----- STL容器初始化 -----" << endl;

    // 1. 默认初始化
    vector<int> vecDefault;
    cout << "vector默认大小: "
         << vecDefault.size() << endl;

    // 2. 带参数初始化
    // 5个元素,值为0
    vector<int> vecParam(5, 0);

    // 3个'x'
    string strParam(3, 'x');
    cout << "vector带参初始化: "
         << vecParam.size()
         << ", string带参: "
         << strParam << endl;

    // 3. 列表初始化(C++11起)
    vector<int>      vecList{1, 2, 3, 4};
    map<int, string> mapList{{1, "one"}, {2, "two"}};
    cout << "vector列表: "
         << vecList[2]
         << ", map列表: "
         << mapList[2]
         << endl;

    // 4. 范围初始化
    vector<int> vecRange(vecList.begin() + 1, vecList.end());
    cout << "范围初始化vector: "
         << vecRange[0]
         << "," << vecRange[1]
         << endl;

    // 指针与动态内存初始化
    cout << "n----- 指针初始化 -----" << endl;

    // 1. 空指针初始化(C++11起推荐nullptr)
    int*  nullPtr1 = nullptr;
    char* nullPtr2 = NULL; // C风格(本质是0)
    cout << "空指针判断: "
         << (nullPtr1 == nullptr ? "nullptr" : "not null")
         << " "
         << (nullPtr2 == NULL ? "NULL" : "not null")
         << endl;

    // 2. 指向已有变量
    int  var      = 100;
    int* ptrToVar = &var;
    cout << "指向变量的指针: "
         << *ptrToVar << endl;

    // 3. 动态分配初始化
    // 初始化单个int
    int* dynInt = new int(200);

    // 动态对象列表初始化
    MyClass* dynObj = new MyClass{3, 9.42, "dynamic"};
    cout << "动态int: "
         << *dynInt
         << ", 动态对象: "
         << dynObj->_c
         << endl;
    delete dynInt;
    delete dynObj;

    // 引用初始化
    cout << "n----- 引用初始化 -----" << endl;

    int refVar = 50;

    // 引用必须初始化,绑定到ref_var
    int& ref = refVar;
    // 常量引用可绑定字面量
    const int& constRef = 100;
    cout << "引用: "
         << ref << ", 常量引用: "
         << constRef << endl;

    // initializer_list函数参数
    cout << "n----- initializer_list函数参数 -----" << endl;

    // 传递列表参数
    PrintList({"apple", "banana", "cherry"});
    return 0;
}

附:参考示例输出


----- 基础类型初始化 -----
局部变量默认初始化: 32156
静态默认初始化: 0
直接初始化: 10, A
拷贝初始化: 20, 3.14
列表初始化: 30
值初始化: 0, 0

----- 数组初始化 -----
局部数组默认初始化: 0,0
静态数组默认初始化: 0,0
C 风格数组初始化: 1 2 3 0 0
C++11数组初始化: 4 5 6
动态数组初始化: 7 8 9 10

----- 类与结构体初始化 -----
调用默认构造函数
默认构造: 0,0
调用带参构造函数
直接初始化: 1,3.14
调用拷贝构造函数
拷贝初始化: 1,direct
调用带参构造函数
类列表初始化: 2,list
调用initializer_list构造函数
initializer_list初始化: 100
聚合类初始化: 10,20.5,aggregate

----- STL容器初始化 -----
vector默认大小: 0
vector带参初始化: 5, string带参: xxx
vector列表: 3, map列表: two
范围初始化vector: 2,3

----- 指针初始化 -----
空指针判断: nullptr NULL
指向变量的指针: 100
调用带参构造函数
动态int: 200, 动态对象: dynamic

----- 引用初始化 -----
引用: 50, 常量引用: 100

----- initializer_list函数参数 -----
apple banana cherry

说明

  • 1.兼容性:标注了 C++11 的特性(如 {} 列表初始化、nullptr、std::initializer_list),其余部分兼容 C++98 及更早版本。
  • 2.安全性:列表初始化({})会阻止窄化转换(例如 int a{3.14}; 会导致编译错误),比 () 更安全。
  • 3.聚合类:无用户定义构造函数、无私有或保护成员的类或结构体,可以直接用 {} 初始化成员。
  • 4.引用特性:引用必须在声明时初始化,且一旦绑定后不能更改指向(与指针不同)。
  • 5.动态内存:new 操作符在 C++11 后支持通过列表初始化动态数组(例如 new int[3]{1, 2, 3})。
此条目发表在C/C++分类目录。将固定链接加入收藏夹。