ð ãã®èšäºã¯ Zenn ã«æçš¿ããå 容ã®ã¢ãŒã«ã€ãã§ãã
ã¯ããã«
C++11 ããå°å
¥ããã emplace_back ã¯ãã³ã³ããã«èŠçŽ ããã®å Žã§æ§ç¯ã§ãã䟿å©ãªã¡ãœããã§ãã
äžæ¹ããã以åãã䜿ãããŠãã push_back ãšã¯ã©ããªéãããããemplace_back ã¯å®å
šã« push_back ã代æ¿ã§ããã®ã§ããããïŒ
æ¬èšäºã§ã¯ã
emplace_backãæ¬åœã«push_backããåžžã«éãã®ãäž¡è ãã©ããªã±ãŒã¹ã«äœ¿ããã®ã
å®è£ ã®éããšæ³šæç¹
ã«ã€ããŠãèªåãªãã«æŽçããèãããŸãšããŸãã
push_back ãš emplace_back ã®éã
push_back
// C++20以é
constexpr void push_back(const T& value); // ã³ããŒ
constexpr void push_back(T&& value); // ã ãŒã
push_back ã¯ããã§ã«çæããããªããžã§ã¯ããã³ããŒãŸãã¯ã ãŒãããŠæ ŒçŽãã颿°ã§ãã
emplace_back
// C++20以é
template<class... Args>
constexpr reference emplace_back(Args&&... args); // ãã®å Žã§æ§ç¯
emplace_back ã¯ãã³ã³ã¹ãã©ã¯ã¿ã«æž¡ãåŒæ°ããã®ãŸãŸåãåããã³ã³ããå
éšã§çŽæ¥ãªããžã§ã¯ããæ§ç¯ããŸãããã®ãããäžéãªããžã§ã¯ããªã ã«èŠçŽ ã远å ã§ããç¹ãç¹åŸŽã§ãã
ãããã®å€§ããªéãã¯ãpush_backãæ¢ã«çæããããªããžã§ã¯ãïŒTåïŒãã³ããŒãŸãã¯ã ãŒãããäžæ¹ã§ãemplace_backã¯ä»»æã®ã³ã³ã¹ãã©ã¯ã¿åŒæ°ãããã®å Žã§Tåã®ã€ã³ã¹ã¿ã³ã¹ãæ§ç¯ã§ããç¹ã§ãã
LLVMã«ãããå éšå®è£
以äžã¯LLVM(libc++)ã«ãããpush_backå
éšã®å®è£
ã§ãã
if (this->__end_ != this->__end_cap()) {
__construct_one_at_end(__x); // æ®ã容éãããå Žåã__xãã³ããŒãŸãã¯ã ãŒãæ§ç¯
} else {
__push_back_slow_path(__x); // è¶³ããªãå Žåãæ°èŠé åã確ä¿ããŠåé
眮
}
__construct_one_at_end ã®äžã§ã¯ãallocatorãæäŸãã construct() ã䜿ã£ãŠãæå®ãããã¡ã¢ãªã«ãªããžã§ã¯ããæ§ç¯ããŠããŸãã
ãŸããallocatorã construct() ãæããªãå Žåã«ã¯åçŽã« in-place new ãåŒã³åºãä»çµã¿ã§ãã
__push_back_slow_path
容éãè¶³ããªãå Žåã¯ã__split_buffer ã䜿ã£ãŠæ°èŠã¡ã¢ãªã確ä¿ããæ¢åèŠçŽ ãã ãŒããŸãã¯ã³ããŒåŸãæ°ããèŠçŽ ã远å ããŠããå
éšãããã¡ãã¹ã¯ããããŸãã
ããã«ããã匷ãäŸå€ä¿èšŒã確ä¿ãããäŸå€ãæããããŠãå ã®ãã¯ã¿ãå£ããªãããã«äœãããŠããã®ããã€ã³ãã§ãã
emplace_back ã®å
éš
éç¹åç emplace_back ã¯ä»¥äžã®ããã«ãä»»æã®åŒæ°ããçŽæ¥èŠçŽ ãæ§ç¯ããŸãã
if (this->__end_ < this->__end_cap()) {
__construct_one_at_end(std::forward<Args>(args)...);
} else {
__emplace_back_slow_path(std::forward<Args>(args)...);
}
slow path ã push_back ãšã»ãŒåãã§ãæ°ããã¡ã¢ãªé åã確ä¿ããŠãããã®å Žã§æ§ç¯ãè¡ã£ãŠããŸãã
倧ããªéã ã¯ã__construct_one_at_end ã«æž¡ãåŒæ°ããTåãã®ãã®ã§ã¯ãªããTã®ã³ã³ã¹ãã©ã¯ã¿åŒæ°ãã§ããç¹ã§ãã
æ§èœé¢ã§ emplace_back ã¯åžžã«æå©ãïŒ
çµè«ããèšããšãå¿ ãããæå©ãšã¯éããŸãã ã
æå©ãªã±ãŒã¹
èŠçŽ ãéããã³ããŒã³ã³ã¹ãã©ã¯ã¿ãæã¡ããã€ã ãŒãã§ããªãå Žåã
ã³ã³ããå éšã§çŽæ¥æ§ç¯ã§ãããšãäžæãªããžã§ã¯ããäžèŠãªã®ã§å¹ççã
åäŸïŒãªãã©ã«ããã®æååæ§ç¯
Arthur O’Dwyer ã®èšäºãDon’t blindly prefer emplace_back to push_backãã§ã¯ã以äžã®Pythonã³ãŒãã§ãã³ãããŒã¯ãåãããŠããŸããã
import sys
print('#include <vector>')
print('#include <string>')
print('extern std::vector<std::string> v;')
for i in range(1000):
print(f'void test{i}() {{')
print(f' v.{sys.argv[1]}_back("{ "A" * i }");')
print('}')
ããã«ãããäŸãã°æ¬¡ã®ãããªåŒã³åºããçæãããŸãã
v.push_back("A");
v.push_back("AA");
v.push_back("AAA");
// ... çç¥ ...
v.emplace_back("A");
v.emplace_back("AA");
v.emplace_back("AAA");
// ... çç¥ ...
çµæ
push_backã§ã¯ãååŒã³åºãã§åã«string(const char*)ãåŒã°ããŸããemplace_backã§ã¯ãªãã©ã«é·ããšã«1000éãã®ç°ãªããã³ãã¬ãŒãå±é ãè¡ãããã³ã³ãã€ã«è² è·ãšå®è¡é床ã«åœ±é¿ãåºãŸãã
ãã³ãããŒã¯ã§ã¯push_backçã1.0sãemplace_backçã4.2sãšãªããæããã«emplace_backãé
ãã±ãŒã¹ãããããšã瀺ãããŸããã
çµè«ïŒäœ¿ãåããéèŠ
å€ãã®å Žåãè€éãªãªããžã§ã¯ããçŽæ¥æ§ç¯ã§ãã
emplace_backãæå©ããã ããåçŽã«æ¢åãªããžã§ã¯ãããªãã©ã«ãã远å ããã ãã®å Žåã¯
push_backã§ãååããã³ãã¬ãŒãå±éã«ããã³ã³ãã€ã«åœ±é¿ãæ°ã«ãªãå Žé¢ã§ã¯ã
push_backãéžã¶ã¹ãã§ãã
ãŸãšã
emplace_backã¯äžéãªããžã§ã¯ããªãã«çŽæ¥æ§ç¯ã§ãããããé«ã³ã¹ããªã³ããŒãé¿ããããå Žé¢ã§ã¯æå©ã§ãããã ããåçŽã«æ¢åãªããžã§ã¯ãããªãã©ã«ãã远å ããã ãã®å Žåããã³ãã¬ãŒãå±éãã³ãŒãèšåŒµãæ§èœé¢ã§ãã€ãã¹ã«ãªãå ŽåããããŸãã
çµå±ã®ãšãããç¶æ³ã«å¿ããŠäœ¿ãåããããšã倧åã§ãã äž¡è ã«ã¯ããããå©ç¹ãšé©çšå Žé¢ããããããããæšæºã©ã€ãã©ãªã«ã¯äºéããçšæãããŠããã®ã§ãã
â» æ¬èšäºã¯ Qiita ã«ãåææçš¿ããŠããŸãã