template <class... Args>
pair<iterator, bool> emplace ( Args&&... args );
emplace 是c++11引入的新特性,用于直接构造和插入元素。
对于unordered_map 和unordered_set ,如果Key值唯一,直接插入一个新元素,使用args作为元素构造函数的参数来构造这个新元素。存在类似的成员函数insert,它将现有对象复制或移动到容器中。
输入:构造新元素的参数。
返回值:如果发生插入(因为没有其他元素存在同一个键),该函数返回一个pair对象,其第一个组件是插入元素的迭代器,第二个组件为true。否则,返回的pair对象将第一个组件作为迭代器,该迭代器使用相同的键指向容器中的元素,并将false作为其第二个组件。
例子:
#include<iostream>
#include<string>
#include<unordered_map>
int main()
{
std::unordered_map<std::string,std::string> mymap;
mymap.emplace(" NCC-1701","J.T. kirk");
mymap.emplace("NCC-1701-D", "J.L. Picard");
mymap.emplace("NCC-74656", "K. Janeway");
std::cout<<"mymap contains:"<<std::endl;
for(auto &x :mymap)
std::cout<<x.first()<< " "<<x.second();
std::cout << std::endl;
return 0;
}
Possible output:
mymap contains: NCC-1701: J.T. Kirk NCC-1701-D: J.L. Picard NCC-74656: K. Janeway |
vector的push_back,map的insert,set的insert。这些插入操作都会涉及到两次构造,首先是对象的初始化构造,接着插入时再复制一次,触发拷贝构造。如果在插入时直接构造,就只需构造一次。
emplace ,emplace_back,emplace_front
引用windpenguin的博客程序,来源:https://blog.csdn.net/windpenguin/article/details/75581552?utm_source=blogxgwz0
来说明emplace 和insert的区别:
// Book结构,保存书本信息
struct SBook
{
SBook() : bookName(""), price(0)
{
std::cout << "default construct: " << bookName << std::endl;
}
SBook(std::string bookName_, int price_) : bookName(bookName_), price(price_)
{
std::cout << "construct: " << bookName << std::endl;
};
SBook(SBook& rhs) : bookName(rhs.bookName), price(rhs.price)
{
std::cout << "copy construct: " << bookName << std::endl;
}
~SBook()
{
std::cout << "deconstruct: " << bookName << std::endl;
}
bool operator <(const SBook& rhs) const
{
return bookName < rhs.bookName;
}
std::string bookName;
int price;
};
// 测试vector
vector<SBook> books;
// 预先分配,否则整个vector在容量不够的情况下重新分配内存
books.reserve(100);
std::cout << "test push_back:" << endl;
books.push_back(SBook("C++从入门到放弃", 1));
std::cout << endl;
std::cout << "test emplace_back:" << endl;
books.emplace_back("水浒传", 2);
std::cout << endl;
std::cout << "test emplace_back default:" << endl;
books.emplace_back();
auto& book = books.back();
book.bookName = "红楼梦";
book.price = 5;
std::cout << endl;
std::cout << "test emplace:" << endl;
auto it = books.emplace(books.end());
it->bookName = "西游记";
it->price = 3;
std::cout << endl;
std::cout << "output all books: " << endl;
for_each(books.begin(), books.end(), [](const SBook& book)->void
{
std::cout << book.bookName << endl;
});
std::cout << endl;
// 测试set
set<SBook> bookSet;
std::cout << "test bookSet insert:" << endl;
bookSet.insert(SBook("十万个为什么", 1));
std::cout << endl;
std::cout<< "test bookSet emplace:" << endl;
bookSet.emplace("新华字典", 2);
std::cout << endl;
std::cout<< "output bookset: " << endl;
for_each(bookSet.begin(), bookSet.end(), [](const SBook&book)->void
{
std::cout << book.bookName << endl;
});
std::cout << endl;
注意:如果在插入元素时发生重排,则与此容器相关的所有迭代器,指针和引用都将失效。否则,只有指向位置和超出位置的那些都是无效的,所有迭代器,指针和对位置之前的元素的引用保证在调用之前保持引用它们所指的相同元素。如果position是end(),并且没有重新排列,则在异常的情况下容器中没有变化(强保证)。
emplace_back造成的引用失效例子:
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<int> ivec;
ivec.emplace_back(1);
ivec.emplace_back(ivec.back());
for (auto it = ivec.begin(); it != ivec.end(); ++it)
cout << *it << " ";
return 0;
}
//输出:
1 -572662307
ivec.back() 返回的是ivec最后一个元素的引用,在emplace_back插入时发生重排,导致对ivec.back()引用失效。
尝试2:不给emplace_back传递引用:
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<int> ivec;
ivec.emplace_back(1);
auto it = ivec.back();
ivec.emplace_back(it);
for (auto it = ivec.begin(); it != ivec.end(); ++it)
cout << *it << " ";
return 0;
}
输出:
1 1
为了避免这个问题:事先预留一定的大小。
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<int> ivec;
ivec.reserve(4);
ivec.emplace_back(1);
ivec.emplace_back(ivec.back());
for (auto it = ivec.begin(); it != ivec.end(); ++it)
cout << *it << " ";
return 0;
}
输出:
1 1
这个时候问题来了,如果不使用emplace_back而改用push_back呢?
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<int> ivec;
ivec.push_back(1);
ivec.push_back(ivec.back());
ivec.push_back(ivec.back());
ivec.push_back(ivec.back());
for (auto it = ivec.begin(); it != ivec.end(); ++it)
cout << *it << " ";
return 0;
}
//输出:1 1 1 1
可见,push_back()插入元素引起重排对back()返回引用没有影响。