• C++11 vector使用emplace_back代替push_back


    C++11中,针对顺序容器(如vector、deque、list),新标准引入了三个新成员:emplace_front、emplace和emplace_back,这些操作构造而不是拷贝元素。这些操作分别对应push_front、insert和push_back,允许我们将元素放置在容器头部、一个指定位置之前或容器尾部。

    当调用push或insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中。而当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。emplace成员使用这些参数在容器管理的内存空间中直接构造元素。

    emplace函数的参数根据元素类型而变化,参数必须与元素类型的构造函数相匹配。emplace函数在容器中直接构造元素。传递给emplace函数的参数必须与元素类型的构造函数相匹配。

    其它容器中,std::forward_list中的emplace_after、emplace_front函数,std::map/std::multimap中的emplace、emplace_hint函数,std::set/std::multiset中的emplace、emplace_hint,std::stack中的emplace函数,等emplace相似函数操作也均是构造而不是拷贝元素。

    emplace相关函数可以减少内存拷贝和移动。当插入rvalue,它节约了一次move构造,当插入lvalue,它节约了一次copy构造。

    下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

    #include "emplace.hpp"
    #include <iostream>
    #include <vector>
    #include <string>
    #include <map>
    #include <tuple>
    #include <utility>
     
    namespace emplace_ {
     
    /////////////////////////////////////////////////////////
    // reference: http://www.cplusplus.com/reference/vector/vector/emplace_back/
    int test_emplace_1()
    {
    {
        /*
            template <class... Args>
            void emplace_back (Args&&... args);
        */
        std::vector<int> myvector = { 10, 20, 30 };
     
        myvector.emplace_back(100);
        myvector.emplace_back(200);
     
        std::cout << "myvector contains:";
        for (auto& x : myvector)
            std::cout << ' ' << x;
        std::cout << '
    ';
    }
     
    {
        /*
            template <class... Args>
            iterator emplace (const_iterator position, Args&&... args);
        */
        std::vector<int> myvector = { 10, 20, 30 };
     
        auto it = myvector.emplace(myvector.begin() + 1, 100);
        myvector.emplace(it, 200);
        myvector.emplace(myvector.end(), 300);
     
        std::cout << "myvector contains:";
        for (auto& x : myvector)
            std::cout << ' ' << x;
        std::cout << '
    ';
    }
     
        return 0;
    }
     
    ///////////////////////////////////////////////////////
    // reference: http://en.cppreference.com/w/cpp/container/vector/emplace_back
    namespace {
    struct President {
        std::string name;
        std::string country;
        int year;
     
        President(std::string p_name, std::string p_country, int p_year)
            : name(std::move(p_name)), country(std::move(p_country)), year(p_year)
        {
            std::cout << "I am being constructed.
    ";
        }
        President(President&& other)
            : name(std::move(other.name)), country(std::move(other.country)), year(other.year)
        {
            std::cout << "I am being moved.
    ";
        }
        President& operator=(const President& other) = default;
    };
    }
     
    int test_emplace_2()
    {
        /*
            The following code uses emplace_back to append an object of type President to a std::vector.
            It demonstrates how emplace_back forwards parameters to the President constructor and shows
            how using emplace_back avoids the extra copy or move operation required when using push_back.
        */
        std::vector<President> elections;
        std::cout << "emplace_back:
    ";
        elections.emplace_back("Nelson Mandela", "South Africa", 1994);
     
        std::vector<President> reElections;
        std::cout << "
    push_back:
    ";
        reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));
     
        std::cout << "
    Contents:
    ";
        for (President const& president : elections) {
            std::cout << president.name << " was elected president of "
                << president.country << " in " << president.year << ".
    ";
        }
        for (President const& president : reElections) {
            std::cout << president.name << " was re-elected president of "
                << president.country << " in " << president.year << ".
    ";
        }
     
        return 0;
    }
     
    ////////////////////////////////////////////////////////////////
    // reference: https://stackoverflow.com/questions/4303513/push-back-vs-emplace-back
    int test_emplace_3()
    {
        /*
            template <class... Args>
            pair<iterator,bool> emplace (Args&&... args);
        */
        typedef std::tuple<int, double, std::string> Complicated;
     
        std::map<int, Complicated> m;
        int anInt = 4;
        double aDouble = 5.0;
        std::string aString = "C++";
     
        // cross your finger so that the optimizer is really good
        //m.insert(/*std::make_pair*/std::pair<int, Complicated>(4, Complicated(anInt, aDouble, aString)));
        m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString)));
     
        // should be easier for the optimizer
        m.emplace(6, Complicated(anInt, aDouble, aString));
        /*
            std::piecewise_construct: This constant value is passed as the first argument to construct a pair object
            to select the constructor form that constructs its members in place by forwarding the elements of two
            tuple objects to their respective constructor.
        */
        m.emplace(std::piecewise_construct, std::make_tuple(8), std::make_tuple(anInt, aDouble, aString));
     
        return 0;
    }
     
    //////////////////////////////////////////////////////////////
    // reference: https://corecplusplustutorial.com/difference-between-emplace_back-and-push_back-function/
    namespace {
    class Dat {
        int i;
        std::string ss;
        char c;
     
    public:
        Dat(int ii, std::string s, char cc) :i(ii), ss(s), c(cc) { }
     
        ~Dat() { }
    };
    }
     
    int test_emplace_4()
    {
        std::vector<Dat> vec;
        vec.reserve(3);
     
        vec.push_back(Dat(89, "New", 'G')); // efficiency lesser
        //vec.push_back(678, "Newer", 'O'); // error,push_back can’t accept three arguments
        vec.emplace_back(890, "Newest", 'D'); // work fine, efficiency is also more
     
        return 0;
    }
     
    } // namespace emplace_
  • 相关阅读:
    Python作业之分页显示内容
    Codeforces Round #368 (Div. 2)
    数论专项测试——约数个数和(lucas的数论)
    数论专题测试——逆元
    数论专题测试——幸运数字
    bzoj2219: 数论之神
    bzoj3283: 运算器
    梅森素数
    后缀数组
    Hash_1014: [JSOI2008]火星人prefix
  • 原文地址:https://www.cnblogs.com/moodlxs/p/10111628.html
Copyright © 2020-2023  润新知