当前位置: 首页 > news >正文

C++统一初始化和初始化列表

一直对C++初始化使用圆括号和花括号的区别有所疑惑,参考书籍和博客简单总结一下

文章目录

  • 常见的初始化操作
  • 统一初始化(Uniform Initialization)
  • 初始化列表(Initializer Lists)


常见的初始化操作

对于一个基础数据类型进行初始化,比如 int

int x(0);
int y = 0;
int z{0};

对于用户定义的类型:

Foo foo1; // default construction
Foo foo2 = foo1; // equivalent to Foo foo2(foo1)
foo1 = foo2; // assignment operation, call operator= function

统一初始化(Uniform Initialization)

C++11之前,初始化一个变量或一个对象,可以使用圆括号()、花括号{} 以及赋值运算符。这就会对初学者产生一定疑惑(具体应该使用哪一种??)。对此,C++11 引入了统一初始化的概念,即对于任意初始化,可以使用一个统一的语法,一个花括号 {},举个栗子:

int values[] {1, 2, 3}; // initialize int array
std::vector<int> v{2, 3, 5, 7, 11, 13, 17}; // initialize vector<int>
std::vector<std::string> cities{"Berlin", "New York", "London", "Braunschweig", "Cairo", "Cologne"}; // implicit conversion: const char * => std::string
std::complex<double> c{4.0, 3.0}; // equivalent to c(4.0, 3.0)

一个初始化列表强迫进行值初始化,基础数据类型初始化为0,指针类型初始化为 nullptr

int i; // i has undefined value
int j{}; // j is initialized by 0
int* p; // p has undefined value
int* q{}; // q is initialized by nullptr

需要注意的是,如果存在收缩转换(narrowing),即精度减小,那么不能使用统一初始化:

int x1(5.3); // OK, but OUCH: x1 becomes 5
int x2 = 5.3; // OK, but OUCH: x2 becomes 5
int x3{5.0}; // ERROR: narrowing
int x4 = {5.3}; // ERROR: narrowing
char c1{7}; // OK: even though 7 is an int, this is not narrowing
char c2{99999}; // ERROR: narrowing (if 99999 doesn’t fit into a char)
std::vector<int> v1 { 1, 2, 4, 5 }; // OK
std::vector<int> v2 { 1, 2.3, 4, 5.6 }; // ERROR: narrowing doubles to ints

初始化列表(Initializer Lists)

为了支持用户定义类型的初始化列表,C++11 提供了模板类 std::initializer_list<>。其可被用于支持使用一列值进行初始化或对一列值进行处理。例如:

void print (std::initializer_list<int> vals)
{
for (auto p=vals.begin(); p!=vals.end(); ++p) { // process a list of values
std::cout << *p << "\n";
}
}
print ({12,3,5,7,11,13,17}); // pass a list of values to print()

当使用统一初始化时,如果构造函数同时匹配指定数量的构造函数以及使用初始化列表的构造函数,优先选择使用初始化列表的构造函数:

class P
{
public:
P(int,int);
P(std::initializer_list<int>);
};
P p(77,5); // calls P::P(int,int)
P q{77,5}; // calls P::P(initializer_list)
P r{77,5,42}; // calls P::P(initializer_list)
P s = {77,5}; // calls P::P(initializer_list)

如果构造函数为显示构造函数,那么不能使用 = 语法进行初始化,因为不能进行隐式转换:

class P
{
public:
P(int a, int b) {
...
}
explicit P(int a, int b, int c) {
...
}
};
P x(77,5); // OK
P y{77,5}; // OK
P z {77,5,42}; // OK
P v = {77,5}; // OK (implicit type conversion allowed)
P w = {77,5,42}; // ERROR due to explicit (no implicit type conversion allowed)void fp(const P&);
fp({47,11}); // OK, implicit conversion of {47,11} into P
fp({47,11,3}); // ERROR due to explicit
fp(P{47,11}); // OK, explicit conversion of {47,11} into P
fp(P{47,11,3}); // OK, explicit conversion of {47,11,3} into P

类似地,使用一个初始化列表的显示构造函数,禁用隐式转换,对于0个、1个或多个初值。

相比于使用圆括号的一个优势,比如当我们使用带参构造函数可以使用如下语法:

Foo foo1(10); // call Foo constrution with arguments

但使用类似语法调用无参构造函数时,却是声明了个函数,而不是创建对象:

Foo foo2(); // declare a foo2 function without arguments and return Foo object
Foo foo2; // foo2 is a default initialized object

我们可以使用花括号来解决这个歧义,因为花括号无法声明为函数

Foo f2{}; // no ambiguity
http://www.lryc.cn/news/186397.html

相关文章:

  • 【重拾C语言】六、批量数据组织(一)数组(数组类型、声明与操作、多维数组;典例:杨辉三角、矩阵乘积、消去法)
  • C++算法:寻找两个正序数组的中位数
  • 2.1 关系数据结构及形式化定义
  • “揭秘淘宝店铺所有商品接口:一键获取海量热销宝贝信息!“
  • 跟着播客学英语-Why I use vim ? part two
  • 【网络通信三要素】TCP与UDP快速入门
  • k8s集群的简单搭建
  • 语义分割笔记(三):通过opencv对mask图片来画分割对象的外接椭圆
  • Nosql redis高可用和持久化
  • 软件工程(1、2;5~7小测参考答案)
  • 服务器存储面临的两大难题
  • Blind Signature盲签名与fabric区块链结合的应用
  • ueditor
  • 2023年台州市第三届网络安全技能大赛(MISC)—Black Mamba
  • 这道面试题工作中经常碰到,但 99% 的程序员都答不上来
  • Linux安装单机PostgreSQL15.4
  • 最新 SpringCloud微服务技术栈实战教程 微服务保护 分布式事务 课后练习等
  • Docker搭建MySQL8.0主从复制(一主一从)
  • 40V汽车级P沟道MOSFET SQ4401EY-T1_GE3 工作原理、特性参数、封装形式—节省PCB空间,更可靠
  • 记录在搭建Jenkins时,所遇到的坑,以及解决方案
  • 二极管“天马行空”的作用,你知道吗?
  • 鼎盛合:adc芯片的五种结构
  • CTF 全讲解:[SWPUCTF 2021 新生赛]Do_you_know_http
  • 物联网AI MicroPython传感器学习 之 4路电容式触摸开关
  • 头戴式耳机什么牌子最好?头戴式耳机推荐性价比高
  • 第 366 场周赛 LeetCode 周赛题解
  • Linux: tcpdump抓包示例
  • seafile server10.0.1 onlyoffice
  • 商城系统选型:Java商城系统还是PHP商城系统好?
  • 【多线程进阶】线程安全的集合类