brace-or-equal initializers(花括号或等号初始化器)各版本异同

学习内容

本节学习花括号 或等号 初始化器在各版本中的异同

初始化器用法:

1、声明时初始化,直接在变量定义时赋值

cpp 复制代码
int age = 11;
string name = "Alice";

int t1(10);
string t2("Hello");
std::vector<int> v(5,0);  // 5个0

int x = {};
string flag = {};
int arr[5] = {};
int x1{}; 
string x2{};

int y1{20};
int arr[]{1,2,3};
std::vector<int> vec{1,2,3};
struct Point p{1,2};

int y = {10};
int arrs[3] = {1,2,3};
std::vector<int> vec = {1 ,2 ,3 };
struct Point{ int x; int y};
Point p = { 100 ,20 };  //聚合类型

Point p = {.y = 50 , .x = 10 };  //按照成员名指定,不用关心顺序 C++20
int arr[5] = {[2] = 20 , [3] = 30 };  //按照索引指定值,C++20

2、new表达式初始化对象/数组

cpp 复制代码
class Person
{
public:
	int age ;
	string name;

	Person(int a,  string n) : age(a) , name(n){}
}

Person* p = new Person(12,"Bob");
cout << p->age << p->name << endl;
//防止泄漏
if (p) delete p;
p = nullptr;

int *arr = new int[5]{1,2,3,4,5};  //初始化元素
delete [] arr;  //必须加[],否则只释放首地址
arr = nullptr;

3、构造函数初始化

cpp 复制代码
class Person
{
public:
	int age ;
	string name;

	Person() = default;
	Person(int a,  string n) : age(a) , name(n){}
}

Person pp;  //无参构造
Person p(12,"Bob"); //有参构造

4、函数参数初始化

cpp 复制代码
void Print(int num , string name)
{
	cout << num << name << endl;
}

Print(101 , "Ana");  //实参调用形参

5、函数返回值初始化

cpp 复制代码
int add(int a , int b)
{
	return a+b;
}

int result = add(3,5);

6、隐式默认初始化,全局变量、类的成员变量(未显式初始化)、静态变量,编译器会自动赋予默认初始化器;局部变量(函数内)需显式赋值才能使用

cpp 复制代码
//全局变量
int g_age;
string g_name;
class A {
public:
	int ages;
	string names;
}

int main()
{
	//直接输出全局变量,未赋值情况
	cout << g_age << g_name<<endl;
	//类成员初始化
	A a;
	cout << a.ages << a.names << endl;
}

7、数组初始化,静态数组、栈内存

cpp 复制代码
int arr1[5] = { 1 ,2 ,3 ,4 ,5 };
int arr2[] = { 1 , 2 , 3 , 4 , 5 };
int arr3[4] = { 1, 2 };  //其他元素默认为0

注:

  • 如果未为对象指定初始化器,那么对象是默认初始化;如果未为引用指定初始化器,编译器报错
  • 如果为对象使用()初始化,那么对象是值初始化;如果为引用指定(),则编译器报错

非局部变量

包含以下类型:

  • 全局变量(整个程序可见)
  • 静态局部变量(函数内部static声明,运行周期多次调用)
  • 类的静态成员变量
    它们都有静态存储器(程序从启动到结束都存在):静态初始化(编译/加载) -> 动态初始化(运行阶段,main之前)

1、静态初始化: 在程序加载时完成,速度快且顺序确定

  • 常量初始化:编译器常量constexpr或字面量,加载时就确定了值
cpp 复制代码
const int a = 10;
static  double pai = 3.14;
constexpr int b = 20;
  • 零初始化器:没有显式初始化值,变量被置为0 / nullptr / false
cpp 复制代码
int x; 
static int y;
char* p;

2、动态初始化: 静态初始化完成后,在main函数执行前,用来处理无法再编译期确定值的初始化(调用函数、依赖其他变量)

  • 无序动态初始化:初始化顺序不确定,例如模版的静态数据成员、变量模板
cpp 复制代码
template < class T>
struct Test{
	static T data; };  //静态模版成员 ,无序动态初始化
template <class T> T Test<T>::data = T{};
  • 部分有序动态初始化:在同个cpp内,若a先于b之前定义并初始化(需要顺序初始化);跨cpp文件仍为无序
cpp 复制代码
inline int a = 1;
inline int b = a;  //a先初始化,然后用a初始化b
  • 有序动态初始化:在同个cpp内,按源代码定义顺序初始化;跨cpp文件顺序完全不确定

3、早期动态初始化

编译器优化方法:把某些本应动态初始化的变量,提前到编译期当成静态初始化处理

需满足以下条件:

  • 初始化过程不会修改其他对象
  • 最终结果和不做优化前的值完全一样

4、延迟动态初始化(优化启动速度,避免不必要的初始化开销)

  • 只要在cpp文件用到此变量,那么它一定会在用之前就完成初始化,没被用到的永远不会初始化
  • 只要有一个被用到且有作用(构造函数里有I/O、修改全局状态、分配资源),同cpp所有这类变量都要初始化
  • 内联变量的动态初始化如果被延迟,保证它在第一次被代码使用前完成初始化
cpp 复制代码
int & GetValue()
{
	static int x = 10;  //用到该函数时,才会静态初始化
	return x;
}

链接器与初始化器限制

  • 若变量有外部/内部链接,在块作用域里声明时不能写初始化器,只能用extern声明,不能同时定义
  • 静态成员数据必须在类外定义并初始化(C++17开始可在类内初始化)
cpp 复制代码
class A
{
public:
	static int data ;
	inline static int element = 19; //C++17开始支持类内初始化
}

int A::data = 14; //类外定义+初始化
  • 非局部变量的析构顺序:遵循初始化的逆序,对于静态局部变量会在程序结束时按照逆序析构,调用std::exit()会触发所有非局部变量的析构,abort()则跳过析构

详情直接点链接查看初始化列表(std::initializer_list)

相关推荐
寻寻觅觅☆5 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
fpcc5 小时前
并行编程实战——CUDA编程的Parallel Task类型
c++·cuda
m0_607076605 小时前
CSS3 转换,快手前端面试经验,隔壁都馋哭了
前端·面试·css3
l1t5 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
赶路人儿6 小时前
Jsoniter(java版本)使用介绍
java·开发语言
NEXT066 小时前
二叉搜索树(BST)
前端·数据结构·面试
NEXT066 小时前
JavaScript进阶:深度剖析函数柯里化及其在面试中的底层逻辑
前端·javascript·面试
ceclar1236 小时前
C++使用format
开发语言·c++·算法
码说AI7 小时前
python快速绘制走势图对比曲线
开发语言·python
Gofarlic_OMS7 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化