初学者的C++11学习:初始化列表和std::initializer_list容器

内容学习自:爱编程的大丙

一、初始化列表

与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段。初始化类的成员有两种方式,一是使用初始化列表,二是在构造函数体内进行赋值操作。

那么为什么要使用初始化列表呢?

主要是性能问题,对于内置类型,如int, float等,使用初始化类表和在构造函数体内初始化差别不是很大,但是对于类类型来说,最好使用初始化列表,为什么呢?因为使用初始化列表少了一次调用默认构造函数的过程,这对于数据密集型的类来说,是非常高效的。

在C++98/03中,对应普通数组和可以直接进行内存拷贝(memcpy())的对象是可以使用初始化列表进行初始化的。

int arryInt[] = {1,2,3,4};//数组初始化列表
double arryDouble[3] = {1.11,2.22,3.33,4.44};//对象,结构体初始化
struct one{
    int id;
    double salary;
}one_man{1001,666.66};

1.几种非指针对象初始化方式:

class test7
{
public:
	test7(int a) { this->a = a; }

	void print() { cout <<a<< endl; }
private:
	int a;
	test7(const test&);
};
void main()
{
//初始化列表测试
	test7 t1(520);
	test7 t2 = 520;
	test7 t3 = { 520 };
	test7 t4{ 520 };
	int a1 = { 1314 };
	int a2{ 1314 };
	int arr1[] = { 1, 2, 3 };
	int arr2[]{ 1, 2, 3 };
	t1.print();
	t2.print();
	t3.print();
	t4.print();

	for (int i : arr1) { cout << arr1[i-1] << endl; }
	for (int i : arr2) { cout << arr2[i-1] << endl; }
}

 t1,t3,t4都是初始化列表的方式初始化对象的,效果都是一样的,在初始时,{} 前面的等号是否书写对初始化行为没有任何影响。t4、a2、arr2 的写法,是 C++11 中新添加的语法格式,使用这种方式可以直接在变量名后边跟上初始化列表,来进行变量或者对象的初始化。

2.指针类型的初始化

int * p = new int{520};
double b = double{52.134};
int * array = new int[3]{1,2,3};
  • 指针p 指向了一个 new 操作符返回的内存,通过列表初始化将内存数据初始化为了 520
  • 变量b 是对匿名对象使用列表初始之后,再进行拷贝初始化。
  • 数组array 在堆上动态分配了一块内存,通过列表初始化的方式直接完成了多个元素的初始化

3.参数列表应用在返回值上

struct person{
    string name;
    int age;
};

person test(person one)
{
    return{one.name,one.age}
}

void main()
{
    person one{"维维亚",24};

    person two = test(one);
}

4.对聚合体的初始化列表

使用列表初始化对对象初始化时,还需要判断这个对象对应的类型是不是一个聚合体,如果是初始化列表中的数据就会拷贝到对象中。

  • 普通数组本身可以看做是一个聚合类型
  • 满足以下条件的类(class、struct、union)可以被看做是一个聚合类型:无用户自定义的构造函数,无私有或保护的非静态数据成员,无基类,无虚函数

注意:倘如存在有参数列表的构造函数,那么就不会使用初始化列表中的数进行赋值。

5.对非聚合体的初始化列表

  • 对于聚合类型的类可以直接使用列表初始化进行对象的初始化,如果不满足聚合条件还想使用列表初始化其实也是可以的,需要在类的内部自定义一个构造函数, 在构造函数中使用初始化列表对类成员变量进行初始化:
struct T1
{
    int x;
    double y;
    // 在构造函数中使用初始化列表初始化类成员
    T1(int a, double b, int c) : x(a), y(b), z(c){}
    virtual void print()
    {
        cout << "x: " << x << ", y: " << y << ", z: " << z << endl;
    }
private:
    int z;
};

void main()
{
    T1 t{ 520, 13.14, 1314 };	// ok, 基于构造函数使用初始化列表初始化类成员
    t.print();
    return 0;
}
  • 另外,需要额外注意的是聚合类型的定义并非递归的,也就是说当一个类的非静态成员是非聚合类型时,这个类也可能是聚合类
struct T1
{
    int x;
    double y;
private:
    int z;
};

struct T2
{
    T1 t1;
    long x1;
    double y1;
};

int main(void)
{
    T2 t2{ {}, 520, 13.14 };
    return 0;
}

t2对象中的第一个参数t1类型可以直接用一个{}来表示。

二、std::initializer_list容器

使用初始化列表也只能进行固定参数的初始化,如果想要做到和 STL 一样有任意长度初始化的能力,可以使用 std::initializer_list 这个轻量级的类模板来实现。

  • 遍历时得到的迭代器是只读的。
  • 轻量级
  • 它可以接收任意长度的初始化列表,但是要求元素必须是同种类型 
  • 内部有三个成员接口:size(), begin(), end()
  •  对象只能被整体初始化或者赋值

使用:

initializer_list<int> list;
list = { 1,2,3,4,5,6,7,8,9,0 };

std::initializer_list的效率是非常高的,它的内部并不负责保存初始化列表中元素的拷贝,仅仅存储了初始化列表中元素的引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值