04-对C++98容器所做的修改
G.1.2 对C++98容器所做的修改
C++11对容器类的方法做了三项主要修改。
首先,新增的右值引用使得能够给容器提供移动语义(参见第18章)。因此,STL现在给容器提供了移动构造函数和移动赋值运算符,这些方法将右值引用作为参数。
其次,由于新增了模板类initilizer_list(参见第18章),因此新增了将initilizer_list作为参数的构造函数和赋值运算符。这使得可以编写类似于下面的代码:
vector<int> vi{100, 99, 97, 98};
vi = {96, 99, 94, 95, 102};
第三,新增的可变参数模板(variadic template)和函数参数包(parameter pack)使得可以提供就地创建(emplacement)方法。这意味着什么呢?与移动语义一样,就地创建旨在提高效率。请看下面的代码段:
class Items
{
double x;
double y;
int m;
public:
Items(); // #1
Items (double xx, double yy, int mm); // #2
...
};
...
vector<Items> vt(10);
...
vt.push_back(Items(8.2, 2.8, 3)); //
调用insert()将导致内存分配函数在vt末尾创建一个默认Items对象。接下来,构造函数Items()创建一个临时Items对象,该对象被复制到vt的开头,然后被删除。在C++11中,您可以这样做:
vi.emplace_back(8.2, 2.8, 3);
方法emplace_back()是一个可变参数模板,将一个函数参数包作为参数:
template <class... Args> void emplace_back(Args&&... args);
上述三个实参(8.2、2.8和3)将被封装到参数args中。参数args被传递给内存分配函数,而内存分配函数将其展开,并使用接受三个参数的Items构造函数(#2),而不是默认构造函数(#1)。也就是说,它使用Items(args…),这里将展开为Items(8.2, 2.8, 3)。因此,将在矢量中就地创建所需的对象,而不是创建一个临时对象,再将其复制到矢量中。
STL在多个就地创建方法中使用了这种技术。