问题引入
拿std::deque的push_back举例,其源码如下:
public: // push_* and pop_*
void push_back(const value_type& t) {
if (finish.cur != finish.last - 1){
// 最后缓冲区尚有一个以上的备用空间
construct(finish.cur, t); //直接在备用空间上构造元素
++finish.cur; //调整最后缓冲区的使用状态
}
else //最后缓冲区已无(或只剩一个)元素备用空间
push_back_aux(t);
}
construct函数的源码如下:
template<typename T1, typename T2>
inline void construct(T1* p, const T2& value) {
new(p)T1(value);
}
这里只探讨元素push_back进容器之后发生了什么事情,主要有三个步骤:
1)调用构造函数,构造临时对象;
2)调用拷贝构造函数,将临时对象放入容器中;
3)调用析构函数,销毁临时变量;
这个过程会造成临时变量申请资源的浪费。
emplace_back
c++11中引入了emplace_back,源码如下:
template<class... _Valty>
decltype(auto) emplace_back(_Valty&&... _Val) //右值引用
{
// insert by perfectly forwarding into element at end, provide strong guarantee
if (_Has_unused_capacity())
{
return (_Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...));
}
//在调用重新构造时,将参数再完美转发出去
_Ty& _Result = *_Emplace_reallocate(this->_Mylast(), _STD forward<_Valty>(_Val)...);
#if _HAS_CXX17
return (_Result);
#else /* ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv */
(void)_Result;
#endif /* _HAS_CXX17 */
}
emplace_back使用了右值引用,调用了构造函数和移动构造函数,提升了效率。
关于右值引用,可以参考:c++11总结03——右值引用_却道天凉_好个秋的博客-CSDN博客
实例分析
void ThreadPool::start(int numThreads)
{
assert(threads_.empty());
running_ = true;
threads_.reserve(numThreads);
for (int i = 0; i < numThreads; ++i)
{
char id[32];
snprintf(id, sizeof id, "%d", i+1);
threads_.emplace_back(new muduo::Thread(
std::bind(&ThreadPool::runInThread, this), name_+id)); //将thread的实例放入threads容器中 提高插入效率
threads_[i]->start();
}
if (numThreads == 0 && threadInitCallback_)
{
threadInitCallback_();
}
}