push_back बनाम emplace_back


761

मैं push_backऔर के बीच के अंतर के बारे में थोड़ा उलझन में हूँ emplace_back

void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);

जैसा कि एक push_backअधिभार एक संदर्भ संदर्भ ले रहा है मैं काफी नहीं देखता कि क्या उद्देश्य emplace_backबन जाता है?



16
ध्यान दें कि (जैसा कि थॉमस नीचे कहता है), प्रश्न में कोड CV 0x के MSVS के अनुकरण से है, न कि वास्तव में C ++ 0x क्या है।
me22

5
पढ़ने के लिए एक बेहतर पेपर होगा: open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2345.pdf । N2642 ज्यादातर स्टैंडर्ड के लिए वर्डिंग है; N2345 वह पेपर है जो विचार को समझाता और प्रेरित करता है।
एलन

ध्यान दें कि MSVC10 में भी एक ऐसा template <class _Valty> void emplace_back(_Valty&& _Val)संस्करण है जो एक सार्वभौमिक संदर्भ लेता है जो explicitएकल तर्क निर्माताओं को पूर्ण अग्रेषण प्रदान करता है ।
जॉकी

संबंधित: क्या कोई मामला है जहां push_backबेहतर है emplace_back? केवल एक मामला मैं सोच सकता हूं कि क्या कोई वर्ग किसी तरह से कॉपी T&operator=(constT&)करने योग्य ( T(constT&)) था, लेकिन निर्माण-सक्षम ( ) नहीं था, लेकिन मैं यह नहीं सोच सकता कि कोई ऐसा क्यों चाहेगा।
बेन

जवाबों:


568

आगंतुक ने क्या कहा इसके अलावा:

void emplace_back(Type&& _Val)MSCV10 द्वारा प्रदान किया गया फ़ंक्शन गैर-अनुरूप और अनावश्यक है, क्योंकि जैसा कि आपने उल्लेख किया है कि यह कड़ाई से समकक्ष है push_back(Type&& _Val)

लेकिन वास्तविक C ++ 0x रूप emplace_backवास्तव में उपयोगी है void emplace_back(Args&&...):;

इसके बजाय value_typeइसे लेने के लिए तर्कों की एक वैरेडिक सूची लेता है, तो इसका मतलब है कि आप अब तर्कों को पूरी तरह से आगे बढ़ा सकते हैं और सीधे एक कंटेनर में एक वस्तु का निर्माण कर सकते हैं जो बिना किसी अस्थायी के है।

यह उपयोगी है क्योंकि कोई फर्क नहीं पड़ता कि कितनी चालाकी से आरवीओ और मेज पर लाए जाने वाले शब्दार्थ अभी भी जटिल मामले हैं जहां एक पुश_बैक अनावश्यक प्रतियां (या स्थानांतरित) करने की संभावना है। उदाहरण के लिए, a के पारंपरिक insert()फ़ंक्शन के साथ std::map, आपको एक अस्थायी बनाना होगा, जिसे बाद में एक में कॉपी किया std::pair<Key, Value>जाएगा, जिसे बाद में मैप में कॉपी किया जाएगा:

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(4, Complicated(anInt, aDouble, aString))); 

// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);

तो उन्होंने MSVC में emplace_back के सही संस्करण को लागू क्यों नहीं किया? वास्तव में, इसने मुझे कुछ समय पहले ही खराब कर दिया था, इसलिए मैंने विजुअल C ++ ब्लॉग पर एक ही सवाल पूछा । यहाँ Microsoft पर Visual C ++ मानक पुस्तकालय कार्यान्वयन के आधिकारिक अनुचर Stephan T Lavavej का जवाब है।

प्रश्न: क्या बीटा २ एम्प्ले अभी कुछ प्रकार के प्लेसहोल्डर हैं?

A: जैसा कि आप जानते हैं, VC10 में वैरेडिक टेम्प्लेट लागू नहीं किए जाते हैं। हम उन चीजों के लिए प्रीप्रोसेसर मशीनरी के साथ अनुकरण करते हैं make_shared<T>(), जैसे , टपल और नई चीजें <functional>। यह प्रीप्रोसेसर मशीनरी का उपयोग करना और बनाए रखना अपेक्षाकृत कठिन है। इसके अलावा, यह संकलन गति को महत्वपूर्ण रूप से प्रभावित करता है, क्योंकि हमें बार-बार सबहेडर्स को शामिल करना होगा। हमारे समय की कमी और संकलन गति की चिंताओं के संयोजन के कारण, हमने अपने इमप्ले फ़ंक्शंस में वैरिएबल टेम्प्लेट की नकल नहीं की है।

जब संकलक में वेरैडिक टेम्प्लेट कार्यान्वित किए जाते हैं, तो आप अपेक्षा कर सकते हैं कि हम पुस्तकालयों में उनका लाभ उठाएँ, जिसमें हमारे ईमेक फ़ंक्शंस भी शामिल हैं। हम अनुरूपता को बहुत गंभीरता से लेते हैं, लेकिन दुर्भाग्य से, हम सब कुछ एक बार में नहीं कर सकते।

यह समझ में आने वाला फैसला है। हर कोई जो एक बार प्रीप्रोसेसर भयानक चाल के साथ वैरेडिक टेम्पलेट का अनुकरण करने की कोशिश करता है, जानता है कि इस सामान को कितना घृणित किया जाता है।


101
यह स्पष्टीकरण कि यह एक MSVS10 मुद्दा है, C ++ मुद्दा यहां सबसे महत्वपूर्ण हिस्सा नहीं है। धन्यवाद।
me22

11
मेरा मानना ​​है कि C ++ कोड की आपकी अंतिम पंक्ति काम नहीं करेगी। pair<const int,Complicated>एक कंस्ट्रक्टर नहीं है जो एक इंट, दूसरा इंट, एक डबल और 4 वें पैरामीटर के रूप में एक स्ट्रिंग लेता है। हालाँकि, आप सीधे इस जोड़ी ऑब्जेक्ट का निर्माण कर सकते हैं इसका टुकड़ा-निर्माणकर्ता का उपयोग करके। वाक्यविन्यास अलग होगा, निश्चित रूप से:m.emplace(std::piecewise,std::forward_as_tuple(4),std::forward_as_tuple(anInt,aDouble,aString));
बेचना

3
खुशी से वैरिएडिक टेम्प्लेट VS2013 में होंगे, जो अब पूर्वावलोकन में हैं।
डैनियल इयरविकर

11
क्या यह उत्तर vs2013 में नए विकास को प्रतिबिंबित करने के लिए अद्यतन किया जाना चाहिए?
becko

6
यदि आप विजुअल स्टूडियो 2013 या उसके बाद का उपयोग कर रहे हैं , तो आपके पास "वास्तविक" के लिए समर्थन होना चाहिए, emplace_backजब तक कि इसे विजुअल C ++ में लागू किया गया था जब वेरिएडिक टेम्प्लेट जोड़े गए थे: msdn.microsoft.com/en-us/library/hh567368। aspx
kayleeFrye_onDeck

200

emplace_backकिसी प्रकार का तर्क नहीं लेना चाहिए vector::value_type, बल्कि इसके बदले में वे तर्क वितर्क करना चाहिए जो कि संलग्न आइटम के निर्माता को भेजे जाते हैं।

template <class... Args> void emplace_back(Args&&... args); 

इसे पास करना संभव है, value_typeजिसे कॉपी कंस्ट्रक्टर को भेज दिया जाएगा।

क्योंकि यह तर्कों को आगे बढ़ाता है, इसका मतलब है कि यदि आपके पास कोई प्रतिद्वंद्विता नहीं है, इसका मतलब यह है कि कंटेनर एक "कॉपी" कॉपी करेगा, न कि एक कॉपी की गई कॉपी।

 std::vector<std::string> vec;
 vec.emplace_back(std::string("Hello")); // moves
 std::string s;
 vec.emplace_back(s); //copies

लेकिन ऊपर जैसा होना चाहिए वैसा ही होना चाहिए push_back। यह संभवतः उपयोग के मामलों की तरह है:

 std::vector<std::pair<std::string, std::string> > vec;
 vec.emplace_back(std::string("Hello"), std::string("world")); 
 // should end up invoking this constructor:
 //template<class U, class V> pair(U&& x, V&& y);
 //without making any copies of the strings

2
@ डेविड: लेकिन तब आप sगुंजाइश में बदल गए हैं , क्या यह खतरनाक नहीं है?
मैथ्यू एम।

2
यदि आप इसके मूल्य के लिए किसी भी लंबे समय के उपयोग की योजना नहीं बनाते हैं तो यह खतरनाक नहीं है। मूविंग एस को अमान्य नहीं बनाता है, यह चालन केवल पहले से किए गए आंतरिक मेमोरी आवंटन को चुरा लेगा और इसे एक डिफ़ॉल्ट स्थिति में छोड़ देगा (कोई स्टिंग आबंटित नहीं) जो तब नष्ट हो जाएगा जब आप बस टाइप किया गया std :: string str;
डेविड

4
@ डेविड: मुझे यकीन नहीं है कि बाद में विनाश को छोड़कर किसी भी उपयोग के लिए एक स्थानांतरित वस्तु से वैध होना आवश्यक है।
बेन Voigt

46
vec.emplace_back("Hello")काम करेगा, क्योंकि const char*तर्क को कंस्ट्रक्टर को भेज दिया जाएगा string। यह पूरा बिंदु है emplace_back
अलेक्जेंड्रे सी।

8
@BenVoigt: एक स्थानांतरित-से-ऑब्जेक्ट को एक मान्य (लेकिन अनिर्दिष्ट) स्थिति में होना आवश्यक है। हालांकि इसका मतलब यह नहीं है कि आप इस पर कोई भी ऑपरेशन कर सकते हैं। विचार करें std::vector। खाली std::vectorएक मान्य स्थिति है, लेकिन आप front()उस पर कॉल नहीं कर सकते । इसका मतलब यह है कि किसी भी फ़ंक्शन के पास कोई पूर्व शर्त नहीं है फिर भी कहा जा सकता है (और विध्वंसक कभी भी पूर्व शर्त नहीं हो सकते हैं)।
डेविड स्टोन

95

emplace_backअगले उदाहरण में प्रदर्शन का अनुकूलन किया जा सकता है।

के लिए emplace_backनिर्माता A (int x_arg)बुलाया जाएगा। और के लिए push_back A (int x_arg)पहले कहा जाता है और move A (A &&rhs)बाद में कहा जाता है।

बेशक, कंस्ट्रक्टर को चिह्नित किया जाना है explicit, लेकिन वर्तमान उदाहरण के लिए खोजकर्ता को निकालना अच्छा है।

#include <iostream>
#include <vector>
class A
{
public:
  A (int x_arg) : x (x_arg) { std::cout << "A (x_arg)\n"; }
  A () { x = 0; std::cout << "A ()\n"; }
  A (const A &rhs) noexcept { x = rhs.x; std::cout << "A (A &)\n"; }
  A (A &&rhs) noexcept { x = rhs.x; std::cout << "A (A &&)\n"; }

private:
  int x;
};

int main ()
{
  {
    std::vector<A> a;
    std::cout << "call emplace_back:\n";
    a.emplace_back (0);
  }
  {
    std::vector<A> a;
    std::cout << "call push_back:\n";
    a.push_back (1);
  }
  return 0;
}

उत्पादन:

call emplace_back:
A (x_arg)

call push_back:
A (x_arg)
A (A &&)

21
कोड उदाहरण के लिए +1 जो प्रदर्शित करता है कि वास्तव में emplace_backबनाम कॉल करते समय क्या होता है push_back
शॉन

मैं यह देखने के बाद यहां आया था कि मेरे पास कोड था जो कॉल कर रहा था v.emplace_back(x);जहां x स्पष्ट रूप से चल-निर्माण योग्य है लेकिन केवल स्पष्ट रूप से प्रतिलिपि-निर्माण योग्य है। तथ्य यह emplace_backहै कि "स्पष्ट रूप से" स्पष्ट रूप से मुझे लगता है कि मेरे जाने के लिए काम करने के लिए समारोह शायद होना चाहिए push_back। विचार?
बेन

यदि आप a.emplace_backदूसरी बार कॉल करते हैं, तो मूव कंस्ट्रक्टर को बुलाया जाएगा!
X-A-12


8

emplace_backअनुरूपता लागू vector<Object>::value_typeहोने पर, वेक्टर के साथ जुड़ने पर कंस्ट्रक्टर को तर्क दिए जाएंगे । मुझे याद है कि विजुअल स्टूडियो ने वैरेडिक टेम्प्लेट का समर्थन नहीं किया था, लेकिन विजुअल स्टूडियो 2013 आरसी में वैरेडिक टेम्प्लेट का समर्थन किया जाएगा, इसलिए मुझे लगता है कि एक अनुरूप हस्ताक्षर जोड़ा जाएगा।

साथ emplace_back, आप सीधे करने के लिए तर्क को आगे अगर vector<Object>::value_typeचल या के लिए copyable होने के लिए निर्माता, आप एक प्रकार की जरूरत नहीं है emplace_backसमारोह, सख्ती से बोला। में vector<NonCopyableNonMovableObject>मामला है, इस के बाद से उपयोगी नहीं है, vector<Object>::value_type एक copyable या चल प्रकार विकसित करने के लिए की जरूरत है।

लेकिन ध्यान दें कि यह आपके लिए उपयोगी हो सकता है std::map<Key, NonCopyableNonMovableObject>, क्योंकि एक बार जब आप नक्शे में एक प्रविष्टि आवंटित करते हैं, तो इसे कभी भी स्थानांतरित या कॉपी करने की आवश्यकता नहीं होती है, इसके विपरीत vector, जिसका अर्थ है कि आप std::mapमैप किए गए प्रकार के साथ प्रभावी ढंग से उपयोग कर सकते हैं जो न तो प्रतिलिपि योग्य है और न ही जंगम।


8

सूचियों के मामले में एक और:

// constructs the elements in place.                                                
emplace_back("element");


//It will create new object and then copy(or move) its value of arguments.
push_back(explicitDataType{"element"});

1

के लिए विशिष्ट उपयोग मामला emplace_back: यदि आपको एक अस्थायी ऑब्जेक्ट बनाने की आवश्यकता है, जिसे बाद में एक कंटेनर में धकेल दिया जाएगा, तो emplace_backइसके बजाय उपयोग करें push_back। यह कंटेनर के भीतर ऑब्जेक्ट को जगह बनाएगा।

टिप्पणियाँ:

  1. push_backउपरोक्त मामले में एक अस्थायी ऑब्जेक्ट बनाएगा और इसे कंटेनर में ले जाएगा। हालाँकि, इन-प्लेस निर्माण के लिए उपयोग किए emplace_backजाने वाले निर्माण और उसके बाद ऑब्जेक्ट को स्थानांतरित करने से अधिक बेहतर होगा (जिसमें आमतौर पर कुछ कॉपी करना शामिल होता है)।
  2. सामान्य तौर पर, आप उपयोग कर सकते हैं emplace_backके बजाय push_backज्यादा मुद्दे के बिना सभी मामलों में। ( अपवाद देखें )
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.