C++中的列表初始化是一种用一对花括号 {} 来进行对象初始化的语法。它被引入主要是为了提供一种统一的初始化方式,适用于各种不同的数据类型和数据结构,包括基本类型、数组、结构体、类、STL 容器等。列表初始化在 C++11 标准中被引入,是现代 C++ 编程风格的一部分。
Type variable = {value1, value2, ...};
int x = {42};double y = {3.14};
int arr[] = {1, 2, 3, 4, 5};
struct Point { int x; int y;};Point p = {10, 20};
class MyClass {public: int data; double value; MyClass(int d, double v) : data(d), value(v) {}};MyClass obj = {42, 3.14};
#include <vector>#include <map>std::vector<int> vec = {1, 2, 3, 4, 5};std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}};
class MyType {public: int x; double y; MyType(int a, double b) : x(a), y(b) {}};MyType myVar = {5, 2.5};
窄转化(Narrowing Conversion)指的是将一个具有较大范围的值转换为较小范围的类型时可能丢失信息的情况。这种转换可能导致截断或失真,因为目标类型的表示范围比源类型小。在 C++ 中,窄转化是一种不安全的类型转换,因为它可能导致数据丢失或意外的行为。
以下是一些示例说明窄转化:
double myDouble = 3.14;int myInt = myDouble; // 窄转化,可能会截断小数部分
long long myLong = 1000000000000;int myInt = myLong; // 窄转化,可能会截断或溢出
long long myLong = 1000000000000;int myInt = static_cast<int>(myLong); // 窄转化,可能会截断或溢出
窄转化是需要小心处理的,因为它可能导致数据的损失和不确定的行为。在需要进行类型转换时,最好使用安全的转换方式,例如使用 static_cast 并在可能丢失信息的地方进行显式的检查和处理。在 C++11 引入的列表初始化中,提供了对缩窄转换的更严格的检查,不允许在列表初始化时发生缩窄转换,从而帮助程序员避免潜在的问题。
列表初始化有一些规则和特点,主要包括以下几个方面:
列表初始化对类型转换更为严格,不允许发生缩窄转换,即不允许将一个精度更高的类型赋值给一个精度较低的类型。
int x = {3.14}; // 错误,尝试缩窄转换
int arr[] = {1, 2, 3}; // 合法,数组大小为3
当列表初始化的类型和目标类型不匹配时,如果存在适当的构造函数,编译器会尝试调用构造函数进行初始化。
class MyClass {public: int data; double value; MyClass(int d, double v) : data(d), value(v) {}};MyClass obj = {42, 3.14}; // 合法,调用构造函数
在某些情况下,可以使用空的花括号 {} 进行初始化,这会被解释为对应类型的默认值。
int x = {}; // x 被初始化为 0double y = {}; // y 被初始化为 0.0
当进行列表初始化时,编译器会根据构造函数的参数匹配规则选择相应的构造函数。
class Example {public: Example(int a, double b); Example(std::string str);};Example obj1 = {42, 3.14}; // 调用构造函数 Example(int, double)Example obj2 = {"Hello"}; // 调用构造函数 Example(std::string)
可以使用嵌套的列表初始化来初始化嵌套的数据结构。
std::vector<std::vector<int>> matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
总体来说,列表初始化提供了一种简洁且直观的初始化语法,同时对类型匹配和转换有着更为严格的规定,减少了一些初始化时可能发生的错误。
列表初始化(Uniform Initialization)在 C++ 中引入的好处主要有以下几点:
int x = {42}; // 初始化基本类型int arr[] = {1, 2, 3}; // 初始化数组Point p = {10, 20}; // 初始化结构体MyClass obj = {42, 3.14}; // 初始化类std::vector<int> vec = {1, 2, 3}; // 初始化容器
int x = {3.14}; // 错误,尝试缩窄转换
class MyClass {public: int data; double value; MyClass(int d, double v) : data(d), value(v) {}};MyClass obj = {42, 3.14}; // 调用构造函数
int arr[] = {1, 2, 3}; // 合法,简洁
"Most Vexing Parse" 是一个有趣而令人困扰的 C++ 编程问题,它通常发生在类的对象声明上,导致程序员可能不是按照他们预期的方式初始化对象。这个问题的名字来源于这种情况的令人迷惑和难以理解。
Most Vexing Parse 主要发生在下面这样的情况:
class MyClass {public: MyClass() {}};int main() { MyClass obj(); // 最令人迷惑的解析,声明了一个函数而不是对象 // ... return 0;}
在上述代码中,MyClass obj(); 被编译器解释为声明一个返回 MyClass 类型的函数而不是创建一个 MyClass 类型的对象。这是因为在 C++ 中,如果声明一个函数的时候带有空括号,编译器会将其解释为一个函数声明而不是一个对象定义。
为了避免 most vexing parse,可以使用以下两种方式之一:
MyClass obj{}; // 使用花括号初始化,避免 most vexing parse
MyClass obj(); // 编译器会将其解释为函数声明MyClass obj{}; // 使用括号初始化,避免 most vexing parse
这个问题是由 C++ 语法规则引起的,对于初学者来说可能会令人困扰。因此,在声明和初始化对象时,特别是在有可能发生 most vexing parse 的地方,建议使用花括号初始化或括号初始化,以避免潜在的问题。
1、类型是一个普通数组,如int[5],char[],double[]等
2、类型是一个类,且满足以下条件:
class NotAggregate {public: int x; int y; NotAggregate(int a, int b) : x(a), y(b) {}};NotAggregate obj = {1, 2}; // 错误,NotAggregate 不是聚合类型
double myDouble = 3.14;int myInt = myDouble; // 合法,但列表初始化会报错
class MyClass {public: MyClass() {}};MyClass obj(); // 最令人迷惑的解析,声明了一个函数而不是对象MyClass obj{}; // 正确的初始化方式
总之,虽然列表初始化是一种很便捷和安全的初始化方式,但在某些情况下,特别是对于非聚合类型和可能导致 most vexing parse 的地方,可能需要考虑其他的初始化方式。
本文链接:http://www.28at.com/showinfo-26-76573-0.htmlC++中列表初始化,你知多少?
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 怎样设计全链路压力测试平台?