C++11/14新特性--区间迭代、初始化列表

本文详细介绍了C++11引入的基于范围的for循环和初始化列表这两项新特性。基于范围的for循环简化了遍历数组和容器的操作,减少了代码量并提高了可读性。初始化列表则统一了对象初始化的方式,包括对类对象和普通数组的初始化。文中通过多个实例展示了这两种新特性的使用方法,包括如何在构造函数中接受初始化列表,以及在new操作、函数返回值等场景的应用。


1、基于范围的for循环

1)基于循环的迭代写法

int array[] = {1,2,3,4,5};
for(auto &x : array)
{
   std::cout << x << std::endl;
}



2)容器遍历

 std::vector<int> arr(5, 100);  //arr数组包含5个100的元素
 
//原来遍历方式
 for (std::vector<int>::iterator i = arr.begin(); i != arr.end(); ++i) 
 {
    std::cout << *i << std::endl;
 }

//C++11遍历方式
 for (auto &i : arr) 
 {
	std::cout << i << std::endl;
 }


2、初始化列表

1)引出问题

在传统 C++ 中,不同的对象有着不同的初始化方法。不同方法都针对各自对象,不能通用。

例如普通数组、POD (plain old data,没有构造、析构和虚函数的类或结构体)类型都可以使用 {}进行初始化,也就是我们所说的初始化列表。而对于类对象的初始化,要么需要通过拷贝构造、要么就需要使用()进行。

比如:

int arr[3] = {1,2,3};   // 列表初始化

class Foo
{
 public:
        Foo(int) { }
 private:
        int value;
};

Foo foo(1); 



2)解决方案

为了解决这个问题,C++11 首先把初始化列表的概念绑定到了类型上,并将其称之为 std::initializer_list,允许构造函数或其他函数像参数一样使用初始化列表,这就为类对象的初始化与普通数组和 POD 的初始化方法提供了统一的桥梁。

例如:

#include <initializer_list>

class Magic
{
public:
    Magic(std::initializer_list<int> list) {}
};

Magic magic = {1,2,3,4,5};
std::vector<int> v = {1, 2, 3, 4};

这种构造函数被叫做初始化列表构造函数,具有这种构造函数的类型将在初始化时被特殊关照。初始化列表除了用在对象构造上,还能将其作为普通函数的形参。

例如:

void func(std::initializer_list<int> list)
{
    return;
}

func({1,2,3});

另外,C++11提供了同一的语法来初始化任意的对象。


实例1

struct A
{
    int a;
    float b;
};
 
struct B
{
    B(int _a, float _b): a(_a), b(_b) {}
 
private:
    int a;
    float b;
};

A a {1, 1.1};    // 统一的初始化语法
B b {2, 2.2};


实例2:通过初始化列表初始化对象

class Foo
{
public:
    Foo(int) {}
private:
    Foo(const Foo &);
};

int main(void)
{
    Foo a1(123);
    Foo a2 = 123;          //error: 'Foo::Foo(const Foo &)' is private
    Foo a3 = { 123 };
    Foo a4 { 123 };
    int a5 = { 3 };
    int a6 { 3 };
    return 0;
}

说明:

  • a3、a4 使用了新的初始化方式来初始化对象,效果如同 a1 的直接初始化。
  • a5、a6 则是基本数据类型的列表初始化方式。可以看到,它们的形式都是统一的。
  • 注意的是,a3 虽然使用了等于号,但它仍然是列表初始化,因此,私有的拷贝构造并不会影响到它。
  • a4 和 a6 的写法,是 C++98/03 所不具备的。在 C++11 中,可以直接在变量名后面跟上初始化列表,来进行对象的初始化。


实例3:普通数组和POD类型的初始化

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

在初始化时,{}前面的等于号是否书写对初始化行为没有影响。


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

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

指针 a 指向了一个 new 操作符返回的内存,通过初始化列表方式在内存初始化时指定了值为 123。


实例5:函数返回值

struct Foo
{
    Foo(int, double) {}
};
Foo func(void)
{
    return { 123, 321.0 };
}

这里的 return 语句就如同返回了一个 Foo(123, 321.0)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值