• emplace_back与push_back方法的区别


    【1】emplace_back源码

     1     template <class... _Valty>
     2     decltype(auto) emplace_back(_Valty&&... _Val) {
     3         // insert by perfectly forwarding into element at end, provide strong guarantee
     4         auto& _My_data   = _Mypair._Myval2;
     5         pointer& _Mylast = _My_data._Mylast;
     6         if (_Mylast != _My_data._Myend) {
     7             return _Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...);
     8         }
     9 
    10         _Ty& _Result = *_Emplace_reallocate(_Mylast, _STD forward<_Valty>(_Val)...);
    11 #if _HAS_CXX17
    12         return _Result;
    13 #else // ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv
    14         (void) _Result;
    15 #endif // _HAS_CXX17
    16     }

    【2】push_back源码

    1     void push_back(const _Ty& _Val) { // insert element at end, provide strong guarantee
    2         emplace_back(_Val);
    3     }
    4 
    5     void push_back(_Ty&& _Val) { // insert by moving into element at end, provide strong guarantee
    6         emplace_back(_STD move(_Val));
    7     }

    【3】两者的区别

    通过几个示例便于理解分析两者应用区别,具体代码如下:

      1 #include <vector>
      2 #include <ctime>
      3 #include <cassert>
      4 #include <iostream>
      5 using namespace std;
      6 
      7 #define EXAMPLE_1
      8 
      9 #ifdef EXAMPLE_13
     10 #define NEED_LOG   (0)
     11 #else
     12 #define NEED_LOG   (1)
     13 #endif
     14 
     15 #define MAXSIZE    (100000)
     16 #define LOOP_COUNT (5)
     17 
     18 class String
     19 {
     20 public:
     21     String();
     22     String(int n, char c);
     23 
     24 #ifdef EXAMPLE_1
     25     explicit String(const char* source);
     26 #else
     27     String(const char* source);
     28 #endif
     29 
     30     String(const String& s);
     31     String(String&& s) noexcept;
     32     String& operator=(char* s);
     33     String& operator=(const String& s);
     34     String& operator=(String&& s);
     35     ~String();
     36 
     37     char& operator[](int i);
     38     const char& operator[](int i) const;
     39     String& operator+=(const String& s);
     40     String& operator+=(const char* s);
     41 
     42     size_t getSize() const;
     43     void setSize(size_t nSize);
     44     char* getData() const;
     45     void setData(char* pData);
     46 
     47 private:
     48     void init();
     49 
     50 private:
     51     size_t m_size;
     52     char* m_data;
     53 };
     54 
     55 void String::init()
     56 {
     57     m_data = new char[1];
     58     assert(m_data != NULL);
     59     *m_data = '\0';
     60     m_size = 0;
     61 }
     62 
     63 String::String()
     64 {
     65     init();
     66 }
     67 
     68 String::String(int n, char c)
     69 {
     70 #if NEED_LOG
     71     cout << "constructor: String(int n, char c) | this: " << this << endl;
     72 #endif
     73     m_data = new char[n + 1];
     74     assert(m_data != NULL);
     75     m_size = n;
     76     char* temp = m_data;
     77     while (n--)
     78     {
     79         *temp++ = c;
     80     }
     81     *temp = '\0';
     82 }
     83 
     84 String::String(const char* source)
     85 {
     86 #if NEED_LOG
     87     cout << "constructor: String(const char* source) | this: " << this << endl;
     88 #endif
     89     if (NULL == source)
     90     {
     91         init();
     92     }
     93     else
     94     {
     95         m_size = strlen(source);
     96         m_data = new char[m_size + 1];
     97         assert(m_data != NULL);
     98         strcpy_s(m_data, (m_size + 1), source);
     99     }
    100 }
    101 String::String(const String& s)
    102 {
    103 #if NEED_LOG
    104     cout << "copy constructor: String(const String& s) | src this: " << &s << " dst this: " << this << endl;
    105 #endif
    106     m_data = new char[s.m_size + 1];
    107     assert(m_data != NULL);
    108     strcpy_s(m_data, (s.m_size + 1), s.m_data);
    109     m_size = s.m_size;
    110 }
    111 
    112 String::String(String&& s) noexcept
    113 {
    114 #if NEED_LOG
    115     cout << "move constructor | src this: " << &s << " dst this: " << this << endl;
    116 #endif
    117     m_data = s.getData();
    118     m_size = s.getSize();
    119     s.setData(NULL);
    120     s.setSize(0);
    121 }
    122 
    123 String& String::operator=(char* s)
    124 {
    125 #if NEED_LOG
    126     cout << "call operator=(char* s)" << endl;
    127 #endif
    128     if (m_data != NULL)
    129     {
    130         delete[]m_data;
    131     }
    132     m_size = strlen(s);
    133     m_data = new char[m_size + 1];
    134     assert(m_data != NULL);
    135     strcpy_s(m_data, (m_size + 1), s);
    136     return (*this);
    137 }
    138 
    139 String& String::operator=(const String& s)
    140 {
    141 #if NEED_LOG
    142     cout << "call operator=(const String& s)" << endl;
    143 #endif
    144 
    145     if (this == &s)
    146     {
    147         return *this;
    148     }
    149     if (m_data != NULL)
    150     {
    151         delete[]m_data;
    152     }
    153     m_size = strlen(s.m_data);
    154     m_data = new char[m_size + 1];
    155     assert(m_data != NULL);
    156     strcpy_s(m_data, (m_size + 1), s.m_data);
    157     return (*this);
    158 }
    159 
    160 String& String::operator=(String&& s)
    161 {
    162 #if NEED_LOG
    163     cout << "call move operator=" << endl;
    164 #endif
    165 
    166     if (this == &s)
    167     {
    168         return (*this);
    169     }
    170     if (m_data != NULL)
    171     {
    172         delete[]m_data;
    173     }
    174     m_data = s.getData();
    175     m_size = s.getSize();
    176     s.setData(NULL);
    177     s.setSize(0);
    178     return (*this);
    179 }
    180 
    181 String::~String()
    182 {
    183 #if NEED_LOG
    184     cout << "call destructor | this: " << this << endl;
    185 #endif
    186 
    187     if (m_data != NULL)
    188     {
    189         delete[]m_data;
    190         m_data = NULL;
    191         m_size = 0;
    192     }
    193 }
    194 
    195 char& String::operator[](int i)
    196 {
    197     return m_data[i];
    198 }
    199 
    200 const char& String::operator[](int i) const
    201 {
    202     return m_data[i];
    203 }
    204 
    205 String& String::operator+=(const String& s)
    206 {
    207     size_t len = m_size + s.m_size + 1;
    208     char* pTemp = m_data;
    209     m_data = new char[len];
    210     assert(m_data != NULL);
    211     strcpy_s(m_data, (m_size + 1), pTemp);
    212     strcat_s(m_data, len, s.m_data);
    213     m_size = len - 1;
    214     delete[]pTemp;
    215     return (*this);
    216 }
    217 
    218 String& String::operator+=(const char* s)
    219 {
    220     if (NULL == s)
    221     {
    222         return (*this);
    223     }
    224     size_t len = m_size + strlen(s) + 1;
    225     char* pTemp = m_data;
    226     m_data = new char[len];
    227     assert(m_data != NULL);
    228     strcpy_s(m_data, (m_size + 1), pTemp);
    229     strcat_s(m_data, len, s);
    230     m_size = len - 1;
    231     delete[]pTemp;
    232     return (*this);
    233 }
    234 
    235 size_t String::getSize() const
    236 {
    237     return m_size;
    238 }
    239 
    240 void String::setSize(size_t nSize)
    241 {
    242     this->m_size = nSize;
    243 }
    244 
    245 char* String::getData() const
    246 {
    247     return m_data;
    248 }
    249 
    250 void String::setData(char* pData)
    251 {
    252     if (NULL == pData)
    253     {
    254         init();
    255     }
    256     else
    257     {
    258         if (m_data != nullptr)
    259         {
    260             delete[]m_data;
    261             m_data = nullptr;
    262         }
    263 
    264         m_size = strlen(pData);
    265         m_data = new char[m_size + 1];
    266         assert(m_data != NULL);
    267         strcpy_s(m_data, (m_size + 1), pData);
    268     }
    269 }
    270 
    271 // 计时器
    272 // 调用clock()函数实现,返回毫秒(ms)数
    273 class TestProgramRunTimer
    274 {
    275     enum { kClockPerSecond = CLOCKS_PER_SEC }; // 每秒时钟的跳数
    276 
    277 public:
    278     TestProgramRunTimer()
    279         : m_cost_time(0)
    280         , m_start_time(0)
    281         , m_end_time(0)
    282     {
    283         start();
    284     }
    285 
    286     ~TestProgramRunTimer()
    287     {}
    288 
    289     void reset()
    290     {
    291         m_cost_time = 0;
    292         m_start_time = 0;
    293         m_end_time = 0;
    294     }
    295 
    296     void start()
    297     {
    298         m_start_time = clock();
    299     }
    300 
    301     void stop()
    302     {
    303         m_end_time = clock();
    304         m_cost_time = (m_end_time - m_start_time) / (kClockPerSecond / 1000.0);
    305     }
    306 
    307     double cost()
    308     {
    309         return m_cost_time;
    310     }
    311 
    312 protected:
    313     double m_cost_time;
    314     clock_t m_start_time;
    315     clock_t m_end_time;
    316 };
    317 
    318 TestProgramRunTimer tt;
    319 
    320 double FV_ByPushBack(vector<String>& testVector)
    321 {
    322     tt.reset();
    323     tt.start();
    324     for (int i = 0; i < MAXSIZE; ++i)
    325     {
    326 #ifndef EXAMPLE_1
    327         testVector.push_back("push_back");
    328 #endif
    329     }
    330     tt.stop();
    331     std::cout << "FV_ByPushBack :: " << tt.cost() << endl;
    332     return tt.cost();
    333 }
    334 
    335 double FV_ByEmplaceBack(vector<String>& testVector)
    336 {
    337     tt.reset();
    338     tt.start();
    339     for (int i = 0; i < MAXSIZE; ++i)
    340     {
    341         testVector.emplace_back("emplace_back");
    342     }
    343     tt.stop();
    344     std::cout << "FV_ByEmplaceBack :: " << tt.cost() << endl;
    345     return tt.cost();
    346 }
    347 
    348 int main()
    349 {
    350     // 显式构造对象:push_back 不支持; emplace_back 支持
    351 #ifdef EXAMPLE_1
    352     {
    353         //String str1 = "kaizen";  // compile error:试图通过隐式转换构造对象,以失败告终:因为参数为const char* source的重载构造函数前加关键字explicit显式限定约束
    354         String str2("kaizen");  // ok:显式构造对象成功
    355 
    356         vector<String> tempVec;
    357         //tempVec.push_back("kaizen"); // compile error:push_back不支持显式构造对象
    358         tempVec.emplace_back("kaizen"); // ok:emplace_bakc支持显式构造对象
    359     }
    360     /*
    361     constructor: String(const char* source) | this: 0000000A3C1DF548
    362     constructor: String(const char* source) | this: 000001325C6D3F80
    363     call destructor | this: 000001325C6D3F80
    364     call destructor | this: 0000000A3C1DF548
    365     */
    366 #endif
    367 
    368     // 隐式构造对象:emplace_back 支持;push_back 支持
    369 #ifdef EXAMPLE_2
    370     {
    371         String str1 = "kaizen"; // ok:通过隐式转换构造对象成功:因为参数为const char* source的重载构造函数前已去掉关键字explicit显式限定约束
    372         String str2("kaizen");  // ok:构造对象成功
    373 
    374         vector<String> tempVec;
    375         tempVec.push_back("kaizen"); // ok:push_back支持隐式转换构造对象
    376         tempVec.emplace_back("kaizen"); // ok:emplace_bakc支持隐式转换构造对象
    377     }
    378     /*
    379     constructor: String(const char* source) | this: 0000002AF413F5A8
    380     constructor: String(const char* source) | this: 0000002AF413F5D8
    381     constructor: String(const char* source) | this: 0000002AF413F708
    382     move constructor | src this: 0000002AF413F708 dst this: 0000020194793670
    383     call destructor | this: 0000002AF413F708
    384     constructor: String(const char* source) | this: 0000020194791610
    385     move constructor | src this: 0000020194793670 dst this: 0000020194791600
    386     call destructor | this: 0000020194793670
    387     call destructor | this: 0000020194791600
    388     call destructor | this: 0000020194791610
    389     call destructor | this: 0000002AF413F5D8
    390     call destructor | this: 0000002AF413F5A8
    391     */
    392 #endif
    393 
    394     // 隐式构造对象:emplace_back 支持;push_back 支持 预留足够空间,避免移动元素影响
    395 #ifdef EXAMPLE_3
    396     {
    397         String str1 = "kaizen"; // ok:通过隐式转换构造对象成功:因为参数为const char* source的重载构造函数前已去掉关键字explicit显式限定约束
    398         String str2("kaizen");  // ok:构造对象成功
    399 
    400         vector<String> tempVec;
    401         tempVec.reserve(10); // 与 example_2的区别
    402         tempVec.push_back("kaizen"); // ok:push_back支持隐式转换构造对象
    403         tempVec.emplace_back("kaizen"); // ok:emplace_bakc支持隐式转换构造对象
    404     }
    405     /*
    406     constructor: String(const char* source) | this: 0000002CAAB2FC58
    407     constructor: String(const char* source) | this: 0000002CAAB2FC88
    408     constructor: String(const char* source) | this: 0000002CAAB2FDB8
    409     move constructor | src this: 0000002CAAB2FDB8 dst this: 0000015D821D5910
    410     call destructor | this: 0000002CAAB2FDB8
    411     constructor: String(const char* source) | this: 0000015D821D5920
    412     call destructor | this: 0000015D821D5910
    413     call destructor | this: 0000015D821D5920
    414     call destructor | this: 0000002CAAB2FC88
    415     call destructor | this: 0000002CAAB2FC58
    416     */
    417 #endif
    418 
    419     // 左值:emplace_back 支持;push_back 支持
    420 #ifdef EXAMPLE_4
    421     {
    422         String str1 = "kaizen1";  // ok:通过隐式转换构造对象成功:因为参数为const char* source的重载构造函数前已去掉关键字explicit显式限定约束
    423         String str2("kaizen2");   // ok:构造对象成功
    424 
    425         vector<String> tempVec;
    426         tempVec.push_back(str1);    // ok
    427         tempVec.emplace_back(str2); // ok
    428     }
    429     /*
    430     constructor: String(const char* source) | this: 00000081A014F4A8
    431     constructor: String(const char* source) | this: 00000081A014F4D8
    432     copy constructor: String(const String& s) | src this: 00000081A014F4A8 dst this: 000002409BE33560
    433     copy constructor: String(const String& s) | src this: 00000081A014F4D8 dst this: 000002409BE31F50
    434     move constructor | src this: 000002409BE33560 dst this: 000002409BE31F40
    435     call destructor | this: 000002409BE33560
    436     call destructor | this: 000002409BE31F40
    437     call destructor | this: 000002409BE31F50
    438     call destructor | this: 00000081A014F4D8
    439     call destructor | this: 00000081A014F4A8
    440     */
    441 #endif
    442 
    443     // 左值:emplace_back 支持;push_back 支持 预留足够空间,避免移动元素影响
    444 #ifdef EXAMPLE_5
    445     {
    446         String str1 = "kaizen1";  // ok:通过隐式转换构造对象成功:因为参数为const char* source的重载构造函数前已去掉关键字explicit显式限定约束
    447         String str2("kaizen2");   // ok:构造对象成功
    448 
    449         vector<String> tempVec;
    450         tempVec.reserve(10); // 与 example_4的区别
    451         tempVec.push_back(str1);    // ok
    452         tempVec.emplace_back(str2); // ok
    453     }
    454     /*
    455     constructor: String(const char* source) | this: 000000534CF9F548
    456     constructor: String(const char* source) | this: 000000534CF9F578
    457     copy constructor: String(const String& s) | src this: 000000534CF9F548 dst this: 000001FF62045660
    458     copy constructor: String(const String& s) | src this: 000000534CF9F578 dst this: 000001FF62045670
    459     call destructor | this: 000001FF62045660
    460     call destructor | this: 000001FF62045670
    461     call destructor | this: 000000534CF9F578
    462     call destructor | this: 000000534CF9F548
    463     */
    464 #endif
    465 
    466     // 右值:emplace_back 支持;push_back 支持
    467 #ifdef EXAMPLE_6
    468     {
    469         vector<String> tempVec;
    470         tempVec.push_back(String{ "kaizen" });    // ok
    471         tempVec.emplace_back(String{ "kaizen" }); // ok
    472     }
    473     /*
    474     constructor: String(const char* source) | this: 000000DF9DB9F9E8
    475     move constructor | src this: 000000DF9DB9F9E8 dst this: 00000258DD4837B0
    476     call destructor | this: 000000DF9DB9F9E8
    477     constructor: String(const char* source) | this: 000000DF9DB9FA18
    478     move constructor | src this: 000000DF9DB9FA18 dst this: 00000258DD481310
    479     move constructor | src this: 00000258DD4837B0 dst this: 00000258DD481300
    480     call destructor | this: 00000258DD4837B0
    481     call destructor | this: 000000DF9DB9FA18
    482     call destructor | this: 00000258DD481300
    483     call destructor | this: 00000258DD481310
    484     */
    485 #endif
    486 
    487     // 右值:emplace_back 支持; push_back 支持; 预留足够空间,避免移动元素影响
    488 #ifdef EXAMPLE_7
    489     {
    490         vector<String> tempVec;
    491         tempVec.reserve(10);  // 与 example_6的区别
    492         tempVec.push_back(String{ "kaizen" });    // ok
    493         tempVec.emplace_back(String{ "kaizen" }); // ok
    494     }
    495     /*
    496     constructor: String(const char* source) | this: 0000005FDD56F8F8
    497     move constructor | src this: 0000005FDD56F8F8 dst this: 0000018316495660
    498     call destructor | this: 0000005FDD56F8F8
    499     constructor: String(const char* source) | this: 0000005FDD56F928
    500     move constructor | src this: 0000005FDD56F928 dst this: 0000018316495670
    501     call destructor | this: 0000005FDD56F928
    502     call destructor | this: 0000018316495660
    503     call destructor | this: 0000018316495670
    504     */
    505 #endif
    506 
    507     // 右值(std::move):emplace_back 支持; push_back 支持;
    508 #ifdef EXAMPLE_8
    509     {
    510         String str1 = "kaizen1";  // ok:通过隐式转换构造对象成功:因为参数为const char* source的重载构造函数前已去掉关键字explicit显式限定约束
    511         String str2("kaizen2");   // ok:构造对象成功
    512 
    513         vector<String> tempVec;
    514         tempVec.push_back(std::move(str1));    // ok
    515         tempVec.emplace_back(std::move(str2)); // ok
    516     }
    517     /*
    518     constructor: String(const char* source) | this: 000000A7B96FFA78
    519     constructor: String(const char* source) | this: 000000A7B96FFAA8
    520     move constructor | src this: 000000A7B96FFA78 dst this: 000001BBEA4E3990
    521     move constructor | src this: 000000A7B96FFAA8 dst this: 000001BBEA4E10D0
    522     move constructor | src this: 000001BBEA4E3990 dst this: 000001BBEA4E10C0
    523     call destructor | this: 000001BBEA4E3990
    524     call destructor | this: 000001BBEA4E10C0
    525     call destructor | this: 000001BBEA4E10D0
    526     call destructor | this: 000000A7B96FFAA8
    527     call destructor | this: 000000A7B96FFA78
    528     */
    529 #endif
    530 
    531     // 右值(std::move):emplace_back 支持; push_back 支持; 预留足够空间,避免移动元素影响
    532 #ifdef EXAMPLE_9
    533     {
    534         String str1 = "kaizen1";  // ok:通过隐式转换构造对象成功:因为参数为const char* source的重载构造函数前已去掉关键字explicit显式限定约束
    535         String str2("kaizen2");   // ok:构造对象成功
    536 
    537         vector<String> tempVec;
    538         tempVec.reserve(10); // 与 example_8 的区别
    539         tempVec.push_back(std::move(str1));    // ok
    540         tempVec.emplace_back(std::move(str2)); // ok
    541     }
    542     /*
    543     constructor: String(const char* source) | this: 0000000D392FF4B8
    544     constructor: String(const char* source) | this: 0000000D392FF4E8
    545     move constructor | src this: 0000000D392FF4B8 dst this: 000001B9A1585910
    546     move constructor | src this: 0000000D392FF4E8 dst this: 000001B9A1585920
    547     call destructor | this: 000001B9A1585910
    548     call destructor | this: 000001B9A1585920
    549     call destructor | this: 0000000D392FF4E8
    550     call destructor | this: 0000000D392FF4B8
    551     */
    552 #endif
    553 
    554 #ifdef EXAMPLE_10
    555     // emplace_back 使用条件:自定义类型必须要有重载(自定义)构造函数,否则只能使用默认构造函数
    556     {
    557         struct Person
    558         {
    559             int id;
    560         };
    561         vector<Person> myTempVec;
    562         myTempVec.emplace_back(Person{});
    563         //myTempVec.emplace_back(2); //compile error:默认构造函数参数为空;再没有任何重载构造函数,编译器不能利用2这个形参完成构造Person对象的使命!
    564     }
    565 #endif
    566 
    567 #ifdef EXAMPLE_11
    568     // 不论哪种方式,传入左值,执行后,对左值无影响
    569     {
    570         String str1 = "kaizen1";
    571         String str2 = "kaizen2";
    572 
    573         vector<String> myTempVec;
    574         std::cout << "before emplace str1:value == " << str1.getData() << endl;
    575         myTempVec.emplace_back(str1);
    576         std::cout << "after emplace str1:value == " << str1.getData() << endl;
    577 
    578         std::cout << "before push str2:value == " << str2.getData() << endl;
    579         myTempVec.push_back(str2);
    580         std::cout << "after push str2:value == " << str2.getData() << endl;
    581     }
    582     /*
    583     constructor: String(const char* source) | this: 00000070548FF998
    584     constructor: String(const char* source) | this: 00000070548FF9C8
    585     before emplace str1:value == kaizen1
    586     copy constructor: String(const String& s) | src this: 00000070548FF998 dst this: 000001B9B73C3260
    587     after emplace str1:value == kaizen1
    588     before push str2:value == kaizen2
    589     copy constructor: String(const String& s) | src this: 00000070548FF9C8 dst this: 000001B9B73C1BB0
    590     move constructor | src this: 000001B9B73C3260 dst this: 000001B9B73C1BA0
    591     call destructor | this: 000001B9B73C3260
    592     after push str2:value == kaizen2
    593     call destructor | this: 000001B9B73C1BA0
    594     call destructor | this: 000001B9B73C1BB0
    595     call destructor | this: 00000070548FF9C8
    596     call destructor | this: 00000070548FF998
    597     */
    598 #endif
    599 
    600 #ifdef EXAMPLE_12
    601     // emplace_back 支持可变参数模板;push_back 支持对象
    602     {
    603         struct Person
    604         {
    605             Person(int id, String name) : m_id(id), m_name(name)
    606             { }
    607 
    608             int m_id;
    609             String m_name;
    610         };
    611         vector<Person> myTempVec;
    612         myTempVec.reserve(10);
    613         //myTempVec.push_back(610580, "kaizen0"); // compile error:不支持
    614         myTempVec.push_back({ 610581, "kaizen1" }); // ok {}列表会先构造临时对象,然后将临时对象传入
    615         //myTempVec.emplace_back({ 601582, "kaizen2" }); // compile error:不支持
    616         myTempVec.emplace_back(Person{ 601583, "kaizen3" }); // ok
    617         myTempVec.emplace_back(601584, "kaizen4");  // ok 因为emplace_back用的是可变参数模板
    618     }
    619     /*
    620     constructor: String(const char* source) | this: 000000A08FAFF6B8
    621     copy constructor: String(const String& s) | src this: 000000A08FAFF6B8 dst this: 000000A08FAFF690
    622     call destructor | this: 000000A08FAFF6B8
    623     move constructor | src this: 000000A08FAFF690 dst this: 0000020EC9594528
    624     call destructor | this: 000000A08FAFF690
    625     constructor: String(const char* source) | this: 000000A08FAFF738
    626     copy constructor: String(const String& s) | src this: 000000A08FAFF738 dst this: 000000A08FAFF710
    627     call destructor | this: 000000A08FAFF738
    628     move constructor | src this: 000000A08FAFF710 dst this: 0000020EC9594540
    629     call destructor | this: 000000A08FAFF710
    630     constructor: String(const char* source) | this: 000000A08FAFF1F8
    631     copy constructor: String(const String& s) | src this: 000000A08FAFF1F8 dst this: 0000020EC9594558
    632     call destructor | this: 000000A08FAFF1F8
    633     call destructor | this: 0000020EC9594528
    634     call destructor | this: 0000020EC9594540
    635     call destructor | this: 0000020EC9594558
    636     */
    637 #endif
    638 
    639 #ifdef EXAMPLE_13
    640     // 两者效率比较:emplace_back略胜一筹 [当然传参的方式不同,可能会有差异,具体场景特殊分析]:
    641     double total_cost_loop_push = 0;
    642     double total_cost_loop_emplace = 0;
    643     for (int i = 0; i < LOOP_COUNT; ++i)
    644     {
    645         vector<String> myVec1, myVec2;
    646         total_cost_loop_push += FV_ByPushBack(myVec1);
    647         total_cost_loop_emplace += FV_ByEmplaceBack(myVec2);
    648         std::cout << std::endl;
    649     }
    650     std::cout << "the average of pushBack : " << total_cost_loop_push / LOOP_COUNT << std::endl;
    651     std::cout << "the average of emplaceBack : " << total_cost_loop_emplace / LOOP_COUNT << std::endl;
    652     /*
    653     FV_ByPushBack :: 245
    654     FV_ByEmplaceBack :: 188
    655 
    656     FV_ByPushBack :: 258
    657     FV_ByEmplaceBack :: 194
    658 
    659     FV_ByPushBack :: 232
    660     FV_ByEmplaceBack :: 181
    661 
    662     FV_ByPushBack :: 215
    663     FV_ByEmplaceBack :: 178
    664 
    665     FV_ByPushBack :: 331
    666     FV_ByEmplaceBack :: 176
    667 
    668     the average of pushBack : 256.2
    669     the average of emplaceBack : 183.4
    670     */
    671 #endif
    672 
    673     system("pause");
    674 }

    【4】结论:建议更多使用emplace_back

    4.1 声明:本地使用VS2019,编译示例应用C++语言标准:ISO C++17标准(std:C++17)

    4.2 提示:示例代码中,可通过修改宏EXAMPLE_的最后编号,逐个分析每个示例的场景。

    4.2 示例说明:

    通过示例1(EXAMPLE_1)情形,说明:

    如果重载构造函数使用explicit修饰,想通过直接利用参数增加对象,则只有使用emplace_back才能通过编译,使用push_back会报编译错误,因为无法进行隐式转换(相比emplace_back,即所谓不支持显式构造对象;或可理解原因也同 行一致)。

    通过示例2(EXAMPLE_2)情形,说明:

    如果重载构造函数没有使用explicit修饰,想通过直接利用参数增加对象,使用emplace_back或push_back均可。原因与示例1反之。

    通过示例3(EXAMPLE_3)情形,说明:

    如果提前可明确欲添加元素数量,预留足够空间,可避免容器扩增空间引起移动元素的消耗。

    通过示例4(EXAMPLE_4)情形,说明:

    如果欲传入左值,使用emplace_back或push_back均可,而且效率相同。

    通过示例5(EXAMPLE_5)情形,说明:

    如果欲传入左值,且提前可明确欲添加元素数量,预留足够空间,可避免容器扩增空间引起移动元素的消耗。

    通过示例6(EXAMPLE_6)情形,说明:

    如果欲传入右值,使用emplace_back或push_back均可,而且效率相同。

    通过示例7(EXAMPLE_7)情形,说明:

    如果欲传入右值,且提前可明确欲添加元素数量,预留足够空间,可避免容器扩增空间引起移动元素的消耗。

    通过示例8(EXAMPLE_8)情形,说明:

    如果欲传入右值(std::move转换后),使用emplace_back或push_back均可,而且效率相同。

    通过示例9(EXAMPLE_9)情形,说明:

    如果欲传入右值(std::move转换后),且提前可明确欲添加元素数量,预留足够空间,可避免容器扩增空间引起移动元素的消耗。

    通过示例10(EXAMPLE_10)情形,说明:

    如果想通过直接利用参数增加对象,emplace_back 的使用条件:自定义类型必须要有重载(自定义)构造函数,否则只能使用默认构造函数。因为总得让编译器知道与参数匹配的构造函数,否则编译器也无能为力。

    通过示例11(EXAMPLE_11)情形,说明:

    不论使用emplace_back或push_back哪种方式,传入左值,执行后,对左值无影响。

    通过示例12(EXAMPLE_12)情形,说明:

    emplace_back 支持可变参数模板,比push_back更方便的优势。

    通过示例13(EXAMPLE_13)情形,说明:

    如果想通过直接利用参数增加对象时,两者效率比较:emplace_back略胜一筹 [当然,传参方式不同,效率可能会相同,具体场景特殊分析,比如左值或右值的示例5和示例7]:

    Good Good Study, Day Day Up.

    顺序 选择 循环 总结

  • 相关阅读:
    unity UGUI实现类似NGUI切换Sprite的方式
    商业智能系统在税务行业的应用
    MSRDS机器人仿真软件学习资源汇总
    Emotiv脑电设备与RDS机器人仿真初步测试
    unity使用UGUI创建摇杆
    如何利用FineBI做财务分析
    Android4.2.2源码目录结构分析
    一个前端妹子的悲欢编程之路
    推荐一款优雅高效的免费在线APP原型工具
    数据分析概述和理论基础
  • 原文地址:https://www.cnblogs.com/Braveliu/p/6625925.html
Copyright © 2020-2023  润新知