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,push_back不支持显式构造对象;也可理解原因同353行一致。

通过示例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.

顺序 选择 循环 总结

posted @ 2017-03-27 11:34  kaizenly  阅读(353)  评论(0编辑  收藏  举报
打赏