Life is short, use emplace_back()。探究一下C++11的push_back, move, rvalue, emplace_back

前言

一直以来写代码,vector想都没想就是push_back,今天发现的C++11的emplace_back碾压了传统的push_back

总结一句话:Life is short, use emplace_back()

简单叙述原因:emplace_back可以“同时构造和插入,一次搞定”,push_back需要“先构造,后插入,而且插入的时候还伴随着拷贝或者移动”。


Talk is cheap, show me the code

#include <iostream>
#include <utility>
#include <chrono>
#include <vector>
#include <string>
using namespace std;
using namespace chrono;


int main()
{
    vector<string> v;
    int num = 100000;
    v.reserve(num);                    // capacity 一次性增大到十万,减少vector多次增大时候的拷贝次数

    cout << "push_back way one:     ";
    auto start = system_clock::now();
    for (int i = 0; i < num; ++i)
    {
        string temp("caitao");
        v.push_back(temp);             // push_back(const string&),参数是左值引用
    }
    auto end = system_clock::now();
    auto duration = duration_cast<microseconds>(end - start);
    cout << duration.count() << " microseconds." << endl << endl;

    cout << "push_back way two:     ";
    v.clear();
    start = system_clock::now();
    for (int i = 0; i < num; ++i)
    {
        string temp("caitao");
        v.push_back(move(temp));       
<think>好的,我现在需要回答用户关于如何在C++11中使用emplace_back以及它如何利用C++11的三大特性的问题。首先,我得回忆一下相关的知识,并整理出结构清晰的回答。 用户提到的三个主要特性,应该是指C++11中的右值引用、移动语义和完美转发。我需要明确emplace_back是如何利用这些特性来提高效率的。同时,用户还希望知道具体的使用方法,所以我需要给出示例代码和说明。 首先,我要确认emplace_back的基本用法。与push_back不同,emplace_back可以直接在容器内构造对象,避免了临时对象的拷贝或移动。这涉及到构造函数的参数直接传递,从而利用完美转发。 接下来,我需要分析每个特性如何被应用。右值引用和移动语义允许资源的高效转移,减少不必要的拷贝。完美转发则确保参数在传递过程中保持其原始类型(左值或右值),从而选择最合适的构造函数。 然后,我需要参考提供的引用内容,特别是引用[1]、[4]和[5],这些提到emplace_backpush_back的区别,以及移动构造函数和拷贝构造函数的影响。例如,引用[3]指出emplace_back并非总是比push_back高效,这可能涉及到是否需要移动或拷贝的情况。 在编写示例代码时,要展示emplace_back直接传递参数构造对象,而push_back需要先创建临时对象。同时,可以加入移动构造函数的例子,说明当使用可移动对象时,emplace_back如何利用移动语义提升性能。 还需要注意,用户可能对何时使用emplace_back有疑问,比如是否需要显式使用std::move,或者当参数较多时如何传递。引用[5]中提到了使用std::move将对象移动到容器中,这可以作为示例的一部分。 最后,总结使用场景,强调emplace_back在构造对象时的优势,以及在需要多次拷贝或移动时的效率提升。同时,提醒用户注意构造函数的匹配问题,确保参数正确传递,避免可能的编译错误。 现在需要组织这些思路,确保回答结构清晰,分点说明特性,并辅以代码示例。同时,按照用户要求,生成相关问题,可能涉及emplace_backpush_back的性能对比、使用注意事项等。</think>在C++11中,`emplace_back` 通过结合 **右值引用**、**移动语义** 和 **完美转发** 三大特性实现高效的对象构造。以下是具体解析和用法示例: --- ### 一、emplace_back的三大特性应用 1. **右值引用** 允许直接绑定到临时对象,避免拷贝开销。例如: ```cpp std::vector<std::string> vec; vec.emplace_back("Hello"); // 直接构造,无需创建临时string对象 ``` 2. **移动语义** 通过移动构造函数转移资源而非深拷贝,适用于可移动对象: ```cpp class MyObject { public: MyObject(MyObject&& other) { /* 移动资源 */ } }; std::vector<MyObject> objs; objs.emplace_back(MyObject()); // 触发移动构造函数 ``` 3. **完美转发** 保持参数原始类型(左值/右值),精确匹配构造函数: ```cpp template <class... Args> void emplace_back(Args&&... args) { // 使用std::forward<Args>(args)...转发参数 allocator.construct(element, std::forward<Args>(args)...); } ``` --- ### 二、emplace_backpush_back对比 | 特性 | `emplace_back` | `push_back` | |------------------|------------------------------------|---------------------------------| | 构造方式 | 直接在容器内构造对象 | 需构造临时对象后拷贝/移动 | | 参数传递 | 支持多参数完美转发 | 仅接受单一对象或右值 | | 性能优势 | 避免临时对象开销(尤其大对象) | 可能触发拷贝或移动操作 | **示例代码:** ```cpp struct Point { Point(int x, int y) : x(x), y(y) {} int x, y; }; std::vector<Point> points; points.emplace_back(3, 4); // 直接调用构造函数 points.push_back(Point(1, 2)); // 需要构造临时对象+移动操作 ``` --- ### 三、高效使用场景 1. **自定义构造函数参数** 传递多个参数构造对象: ```cpp vec.emplace_back("text", 100, 3.14); // 匹配多参数构造函数 ``` 2. **管理不可拷贝对象** 如`std::unique_ptr`: ```cpp std::vector<std::unique_ptr<MyClass>> ptrs; ptrs.emplace_back(new MyClass()); // 直接构造,无需std::move ``` 3. **显式移动语义优化** 配合`std::move`转移资源: ```cpp std::string s = "data"; vec.emplace_back(std::move(s)); // 强制触发移动构造函数 ``` --- ### 四、注意事项 1. **构造函数匹配** 需确保参数类型与目标构造函数严格匹配,否则可能导致隐式转换或编译错误[^4]。 2. **性能陷阱** 对于简单类型(如`int`),`emplace_back`与`push_back`性能差异可忽略[^3]。 3. **代码可读性** 复杂参数时优先考虑可维护性,例如: ```cpp // 推荐写法:明确构造过程 vec.push_back({arg1, arg2}); // vs vec.emplace_back(arg1, arg2); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值