C++11 之列表初始化

2023-10-30

在 c++ 98/03 中的对象初始化方法有很多种,请看下面的代码:

//初始化列表
int i_arr[3] = {1, 2, 3};  //普通数组

struct A {
    int x;
    struct B {
        int i;
        int j;
    } b;
} a = {1, {2, 3}};  // POD 类型即 plain old data 类型,简单来说,是可以直接使用 memcpy 复制的对象。

//拷贝初始化(copy-initialization)
int i = 0;
class Foo {
public:
    Foo(int) {}
} foo = 123;  //需要拷贝构造函数

//直接初始化(direct-initialization)
int j(0);
Foo bar(123);

这些不同的初始化方法,都有各自的适用范围和作用。最关键的是,这些种类繁多的初始化方法,没有一种可以通用所有情况。

为了统一初始化方式,并且让初始化行为具有确定的效果,c++11 中提出了列表初始化(List-initialization)的概念,在 c++11 中可以直接在变量名后面加上初始化列表来进行对象的初始化

struct A {
public:
    A(int) {}

private:
    A(const A&) {}
};

int main() {
    A a(123);
    A b = 123;  // error: 'A::A(const A &)' is private
    A c = {123};
    A d{123};  // c++11

    int e = {123};
    int f{123};  // c++11
    return 0;
}

int i_arr[3] { 1, 2, 3 };  //普通数组
struct A {
    int x;
    struct B {
        int i;
        int j;
    } b;
} a { 1, { 2, 3 } };  //POD类型

在上例中,c、d 使用了新的初始化方式来初始化对象,效果如同 a 的直接初始化;e、f 则是基本数据类型的列表初始化方式。可以看到,它们的形式都是统一的。
【注意1】c 虽然使用了等于号,但它仍然是列表初始化,因此,私有的拷贝构造并不会影响到它。d 和 f 的写法,是 c++98/03 所不具备的。
【注意2】在初始化时,{} 前面的等于号是否书写对初始化行为没有影响。

另外,new 操作符等可以用圆括号进行初始化的地方,也可以使用初始化列表:

int* a = new int { 123 };  
double b = double { 12.12 };  
int* arr = new int[3] { 1, 2, 3 };

指针 a 指向了一个 new 操作符返回的内存,通过初始化列表方式在内存初始化时指定了值为 123;b 则是对匿名对象使用列表初始化后,再进行拷贝初始化;让人眼前一亮的是 arr 的初始化方式,堆上动态分配的数组终于也可以使用初始化列表进行初始化了。

列表初始化也可以用在函数的返回值上:

std::vector<int> func() { 
	return {};  // return 语句就如同返回了一个 func()
}

列表初始化的一些规则:聚合类型可以进行直接列表初始化。那什么是聚合类型:

  • 类型是一个普通数组,如 int[5],char[],double[] 等
  • 类型是一个类,且满足以下条件:
    • 没有用户声明的构造函数
    • 没有用户提供的构造函数(允许显示预置或弃置的构造函数)
    • 没有私有或保护的非静态数据成员
    • 没有基类
    • 没有虚函数
    • 没有 {} 和 = 直接初始化的非静态数据成员
    • 没有默认成员初始化器
struct A {
    int a;
    int b;
    int c;
    A(int, int) {}
};

int main() {
    A a{1, 2, 3};  // error,A有自定义的构造函数,不能列表初始化
}

上述代码类 A 不是聚合类型,无法进行列表初始化,必须以自定义的构造函数来构造对象。

struct A {
    int a;
    int b;
    virtual void func() {}  // 含有虚函数,不是聚合类
};

struct Base {};
struct B : public Base {  // 有基类,不是聚合类
    int a;
    int b;
};

struct C {
    int a;
    int b = 10;  // 有等号初始化,不是聚合类
};

struct D {
    int a;
    int b;
private:
    int c;  // 含有私有的非静态数据成员,不是聚合类
};

struct E {
    int a;
    int b;
    E() : a(0), b(0) {}  // 含有默认成员初始化器,不是聚合类
};

上面列举了一些不是聚合类的例子,对于一个聚合类型,使用列表初始化相当于对其中的每个元素分别赋值;对于非聚合类型,需要先自定义一个对应的构造函数,此时列表初始化将调用相应的构造函数

std::initializer_list

我们平时开发使用 STL 过程中可能发现它的初始化列表可以是任意长度,大家有没有想过它是怎么实现的呢,答案是 std::initializer_list,看下面这段示例代码:

struct CustomVec {
    std::vector<int> data;
    CustomVec(std::initializer_list<int> list) {
        for (auto iter = list.begin(); iter != list.end(); ++iter) {
            data.push_back(*iter);
        }
    }
};

我想通过上面这段代码大家可能已经知道STL是如何实现的任意长度初始化了吧,这个 std::initializer_list 其实是作为函数参数。
【注意】std::initializer_list<T>,它可以接收任意长度的初始化列表,但是里面必须是相同类型T,或者都可以转换为T。

列表初始化的好处

  • 方便,且基本上可以替代括号初始化,统一了初始化方式
  • 可以使用初始化列表接受任意长度
  • 可以防止[[01_C 语法#^88ad66|类型窄化]],避免精度丢失的隐式类型转换
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++11 之列表初始化 的相关文章

随机推荐

  • kmeans算法实现及获取anchors

    kmeans算法网上资料很多 其原理简单来说就选取k个聚类中心 然后把剩余的点归类到与其相距最近的聚类中心 是一种无监督算法 缺点和不足有两个 第一个是k需要指定 第二个是对于聚类中心种子点的选取很敏感 本文将以yolov4算法使用kmea
  • Python 基础教程——语法

    前言 Python 语言与 Perl C 和 Java 等语言有许多相似之处 但是 也存在一些差异 这次我们将来学习 Python 的基础语法 让你快速学会 Python 编程 第一个 Python 程序 交互式编程 交互式编程不需要创建脚
  • RocketMQ第四节(部署模式、监控面板等)

    1 mq的部署模式 部署方式 RocketMQ 参考官网 单机模式 抗风险能力差 单机挂机没服务 单机硬盘损坏 丢失数据 多机 多master没有Slave副本 多个master采用RAID10磁盘 不会丢失数据 但是某一个master关闭
  • Unity - BRP - PP后效导致 Camera.targetTexture 被换掉,graphicsFormat 不对问题

    文章目录 环境 目的 原因 问题 解决方法 环境 Unity 国际版2020 3 37f1 Pipeline BRP Packages Post Processing 3 0 3 目的 BRP 虽然是 官方放弃更新的 渲染管线 但是有些项目
  • java--基础--17.8--线程--wait方法与sleep方法区别

    java 基础 17 8 线程 wait方法与sleep方法区别 1 介绍 wait 线程间的通讯的问题 需要等待别的线程唤醒 sleep 自己控制线程的运行状态 隔了一段时间自动醒过来 wait 方法释放了锁 sleep 方法没有释放锁
  • 高斯分布(正态分布)详解

    高斯分布 一 概念 二 详解和例子说明 三 判断数据是否服从高斯分布 四 高斯分布实际应用 一 概念 定义 随机变量X服从一个数学期望 mu 方差为 sigma 的高斯分布 又名正态分布 当 0 1时的正
  • c, cs, vala 性能简单测试

    分别用c cs 和 vala 完成同样的运算 Code include
  • matlab sum函数_Matlab: 如何对矩阵的部分行/列求和

    Matlab里的sum函数可以用于求和 先简单来介绍一下sum函数 对一个矩阵A而言 1 sum A all 对矩阵A的所有元素进行求和 返回的是一个标量 2 sum A 1 对矩阵A的每一列进行求和 返回的是一个行向量 3 sum A 2
  • 哈工大2020软件构造Lab4实验报告

    为了鄙视代写 抄袭 伸手党 删除了一些 容易抄袭 的部分 有问题 询问省略部分 欢迎QQ交流 本项目于5 19日实验课完成 该更新的 更新完成 如果有所参考 请点点关注 点点赞GitHub Follow一下谢谢 2020春计算机学院 软件构
  • Python安装教程

    本文主要介绍Windows下Python的安装步骤 1 打开官网www python org 选择Downloads 进入下载界面 2 选择需要下载的Python版本号 点击Download 我选择的Python版本为3 9 6 3 点击D
  • 计算机考研复试操作系统题库

    文章目录 1 什么是操作系统 操作系统的主要功能是 它的主要特征是什么 重点 2 进程与线程的关系以及区别 重点 3 Windows下的内存是如何管理的 简单了解即可 4 中断和轮询的特点 5 什么是临界区 如何解决冲突 什么叫临界资源 6
  • JDBC基础

    1 JDBC概述 在开发中我们使用的是java语言 那么势必要通过java语言操作数据库中的数据 1 1 JDBC概念 JDBC 就是使用Java语言操作关系型数据库的一套API 全称 Java DataBase Connectivity
  • 踏浪点神:新手该如何避免频繁重仓交易?

    期货市场中最忌讳的就是让情绪影响交易 但很多人却又很难避免这一点 其中表现最为突出的就是频繁操作了 自信地以为 多劳多得 近乎疯狂地买卖 满脑子的愤怒都急切地想要通过 自杀 的方式得以宣泄 这就是所谓的 交易失控 大多数人在事后冷静下来了都
  • K8S内容分发网络之集群,nginx,负载均衡,防火墙

    目录 第一章 实验架构需求 第二章 实验环境准备 2 1 节点准备 2 2 环境准备 2 3 在master node01 node02上操作安装docker 2 4 所有节点安装kubeadm kubelet和kubectl 2 5 部署
  • 使用dplyr包中的rename函数重命名R语言数据框中的指定列

    使用dplyr包中的rename函数重命名R语言数据框中的指定列 在R语言中 dplyr包提供了一组功能强大且易于使用的函数 用于对数据进行操作和转换 其中 rename函数可以用于重命名数据框中的指定列 本文将介绍如何使用dplyr包中的
  • DVWA(七) - 使用python脚本实现SQL盲注

    SQL Injection Blind sql盲注其实就是sql注入的一种 但是不会根据sql注入的攻击语句返回你想要知道的信息 盲注分为两种 布尔盲注以及时间盲注 布尔盲注 根据你的注入信息返回True和Fales 而返回的True和Fa
  • 【Java入门学习笔记】——第六天 import语句,类的访问控制权限问题,对象数组

    Q 怎样使用import语句 A import语句的作用如下 1 引入类库中的类 2 引入自定义包中的类 需要把程序使用的自定义的包名所形成的目录都放在同一文件夹中 Example01 所有包名形成的目录都要放在Example01中 stu
  • 职业素质学习心得

    名言 1 古之立大事者 不惟有超世之才 必有坚韧不拔之志 2 摒弃侥幸之念 必取百炼成刚 厚积分秒之功 始得一鸣惊人 一 心态决定一切 如果你有一个梦想 维护她 坚守她 实现她 企业招聘看重两个方面 心态 积极 能力 强大 公司待遇衡量标准
  • iOS反编译修改ipa的启动图

    启动图制作脚本点击此获取 步骤一 先创建一个iOS项目 并制作启动图 点击获取教程链接 步骤二 运行上述创建的项目 将会在Products目录得到一个xx app 右键选择 Show in Finder 再右键选择 显示包内容 取出Laun
  • C++11 之列表初始化

    在 c 98 03 中的对象初始化方法有很多种 请看下面的代码 初始化列表 int i arr 3 1 2 3 普通数组 struct A int x struct B int i int j b a 1 2 3 POD 类型即 plain