- 如果是直接插入对象
push_back()
和emplace_back()
没有区别 - 但如果直接传入构造函数所需参数,
emplace_back()
会直接在容器底层构造对象,省去了调用拷贝构造或者移动构造的过程
class Test
{
public:
Test(int a)
{
cout<<"Test(int)"<<endl;
}
Test(int a,int b)
{
cout<<"Test(int,int)"<<endl;
}
Test(const Test&)
{
cout<<"Test(const Test&)"<<endl;
}
~Test()
{
cout<<"~Test()"<<endl;
}
Test(Test&&)
{
cout<<"Test(Test&&)"<<endl;
}
};
int main()
{
Test t1(10);//Test(int)
vector<Test> v;
v.reserve(100);
cout<<"========1=========="<<endl;
//直接插入对象,两个没有区别
v.push_back(t1);//Test(const Test&)
v.emplace_back(t1);//Test(const Test&)
cout<<"=========2========="<<endl;
//直接插入对象,两个没有区别
v.push_back(Test(20));//Test(int) Test(Test&&) ~Test()
v.emplace_back(Test(20));//Test(int) Test(Test&&) ~Test()
cout<<"=========3========="<<endl;
//给emplace传入Test对象构造所需的参数,直接在容器底层构造对象即可
v.emplace_back(20);//Test(int)
v.emplace_back(30,40);//Test(int,int)
cout<<"=========4========="<<endl;
/*
map<int,string> mp;
m.insert(make_pair(10,"zhangsan"));//构造临时对象 调用右值引用拷贝构造 析构临时对象
m.emplace(10,"zhangsan") ;//在map底层直接调用普通构造函数,生成一个pair对象即可
*/
return 0;
}
底层实现:
//空间配置器
template<typename T>
struct Allocator
{
T* allocate(size_t size)//负责内存开辟
{
return (T*)malloc(sizeof(T)*size);
}
template<typename... Types>
void construct(T *ptr,Types&&... args)//负责构造
{
new (ptr) T(std::forward<Types>(args)...);//定位new 在指定的内存上 构造一个值为val的对象,会调用 T类型的拷贝构造
}
};
template<typename T,typename Alloc = Allocator<T>>
class vector
{
public:
vector():vec_(nullptr),size_(0),idx_(0){}
void reserve(size_t size)
{
vec_ = allocator.allocate(size);
size_ = size;
}
template<typename Type>
void push_back(Type&& val)
{
allocator.construct(vec_+idx_,std::forward<Type>(val));
idx_++;
}
template<typename... Types>
void emplace_back(Types&&... args)
{
allocator.construct(vec_+idx_,std::forward<Types>(args)...);
idx_++;
}
private:
T* vec_;
int size_;//内存大小
int idx_;
Alloc allocator;//空间配置器
};