C++11引入三个新成员-emplace_front, emplace和emplace_back ,可以方便地在容器中进行构造元素的操作,用于在容器中直接构造对象,从而减少不必要的拷贝或者移动操作,提高代码效率和性能。
这些操作分别对应push_front, insert和push_back,能够让我们把元素放置在容器头部,一个指定位置之前或容器尾部。
c.emplace_back(t)在c的尾部创建一个值为t的元素
c.emplace_front(t) 在c的头部创建一个值为t的元素
c.emplace(p,t) 在迭代器p所指向的元素之前创建一个值为t的元素,返回指定新添加元素的迭代器
#include <bits\stdc++.h> using namespace std; class Test { public: Test(int a){cout<<"Test(int)"<<endl;} Test(int a, int b) {cout<<"Test(int, int)"<<endl;} ~Test(){cout<<"~Test()"<<endl;} Test(const Test&) {cout <<"Test(const Test&)"<<endl;} //左值引用 Test(Test&&) {cout<<"Test(Test&&)"<<endl;} //右值引用 }; int main() { Test t1(10); vector<Test> v; v.reserve(100); cout<<"=========="<<endl; //直接插入两个对象 没有区别 v.push_back(t1); v.emplace_back(t1); cout<<"=========="<<endl; //插入两个临时对象 也没有区别 v.push_back(Test(20)); v.emplace_back(Test(20)); cout<<"=========="<<endl; //只需要传入参数 直接调用相应参数类型函数 构造新对象 //避免了额外的对象拷贝或移动操作,可以更高效地构造元素。 v.emplace_back(20); v.emplace_back(30,40); cout<<"=========="<<endl; return 0; }
- 当调用push或insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中。
- 而当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。
- emplace成员使用这些参数在容器管理的内存空间中直接构造元素。
#include <bits\stdc++.h>
#include <iostream>
#include <vector>
using namespace std;
class Test
{
public:
Test(int a) { cout << "Test(int)" << endl; }
Test(int a, int b) { cout << "Test(int, int)" << endl; }
~Test() { cout << "~Test()" << endl; }
Test(const Test&) { cout << "Test(const Test&)" << endl; } //左值引用
Test(Test&&) { cout << "Test(Test&&)" << endl; } //右值引用
};
//实现容器的空间配置器
template<typename T>
struct MyAllocator
{
// allocate deallocate 开辟内存 释放内存
// construct destory 创建对象 销毁对象
T* allocate(size_t size)
{
return (T*)malloc(size * sizeof(T)); //用 malloc 分配一块内存空间,并返回指向该内存的指针
}
template<typename... Types>
void construct(T* ptr, Types&&... args)
{
// args只是一个参数,而且是个Test对象,T也是Test类型
// 还是需要类型完美转发
new(ptr)T(std::forward<Types>(args)...);
}
};
//第一个参数是容器中放得内容类型 第二个参数是空间配置器类型
template<typename T, typename Alloc = MyAllocator<T>>
class vector
{
public:
//默认构造函数
vector() : vec_(nullptr), size_(0), idx_(0){}
//预留空间
void reserve(size_t size)
{
vec_ = allocator_.allocate(size);
size_ = size;
}
//----------------------------------------------------------
//push_back
//void push_back(const T& val) //左值
//{
// allocator_.construct(vec_ + idx_, val);
// idx++;
//}
//void push_back(T&& val) //右值
//{
// allocator_.construct(vec_ + idx_, std::move(val));
// idx++;
//}
//
// 引用折叠
template<typename Type>
void push_back(Type&& val)
{
allocator_.construct(vec_ + idx_, std::forward<Type>(val));
idx++;
}
//------------------------------------------------------------
// 1.引用折叠 + 可变参数模板
template<typename... Types>
void emplace_back(Types&&... args) //可接受多个数量参数
{
//不管是左值还是右值引用变量,本身都是个左值
//传递的过程中要保持传递参数的类型不变 需要使用forward完美转发
allocator_.construct(vec_ + idx_, std::forward<Types>)(args)...);
idx_++;
}
private:
T* vec_; //指向类型T的指针
int size_; //空间大小
int idx_; //当前索引位置
Alloc allocator_; //使用的空间配置器对象
};
int main()
{
Test t1(10);
vector<Test> v;
v.reserve(100);
cout << "==========" << endl;
//直接插入两个对象 没有区别
v.push_back(t1);
v.emplace_back(t1);
cout << "==========" << endl;
//插入两个临时对象 也没有区别
v.push_back(Test(20));
v.emplace_back(Test(20));
cout << "==========" << endl;
//只需要传入参数 直接调用相应参数类型函数 构造新对象
//避免了额外的对象拷贝或移动操作,可以更高效地构造元素。
v.emplace_back(20);
v.emplace_back(30, 40);
cout << "==========" << endl;
/*
map<int,string> m;
m.insert(make_pair(10,"zhang san");
m.emplace(10,"zhang san"); =>在map底层直接调用普通构造函数,生成一个pair对象即可
*/
return 0;
}