পুশ_ব্যাক বনাম এমপ্লে_ব্যাক


761

আমি push_backএবং এর মধ্যে পার্থক্য সম্পর্কে কিছুটা বিভ্রান্ত হয়ে পড়েছি emplace_back

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

যেমন আছে একটি push_back জমিদার একটি rvalue রেফারেন্স আমি বেশ কি উদ্দেশ্য দেখতে না গ্রহণ emplace_backহয়ে?



16
নোট করুন (যেমন থমাস নীচে বলেছেন), প্রশ্নের কোডটি এমএসভিএসের সি ++ 0x এর অনুকরণ থেকে , সি ++ 0x আসলে কী নয়।
me22

5
পড়ার জন্য আরও ভাল কাগজটি হ'ল : ওপেন-std.org/jtc1/sc22/wg21/docs/papers/2007/n2345.pdf । N2642 বেশিরভাগ ক্ষেত্রে স্ট্যান্ডার্ডের জন্য শব্দযুক্ত; এন 2345 হল এমন কাগজ যা ধারণাটি ব্যাখ্যা করে এবং প্রেরণা দেয়।
অ্যালান

মনে রাখবেন যে এমনকি এমএসভিসি 10 তে একটি template <class _Valty> void emplace_back(_Valty&& _Val)সংস্করণ রয়েছে যা সর্বজনীন রেফারেন্স নেয় যা explicitএকক যুক্তি নির্মাণকারীকে নিখুঁত ফরোয়ার্ডিং সরবরাহ করে ।
জোকি

সম্পর্কিত: এমন কোনও মামলা আছে যেখানে push_backতার চেয়ে বেশি পছন্দনীয় emplace_back? আমি কেবলমাত্র সেই ক্ষেত্রেই ভাবতে পারি যে যদি কোনও শ্রেণি কোনওরকমভাবে অনুলিপিযোগ্য ( T&operator=(constT&)) তবে নির্মাণ-সক্ষম ( T(constT&)) না হত তবে কেন কেন কখনও এটি চাইবে তা আমি ভাবতে পারি না।
বেন

উত্তর:


568

দর্শনার্থী যা বলেছেন তা ছাড়াও:

void emplace_back(Type&& _Val)এমএসসিভি 10 দ্বারা প্রদত্ত ফাংশনটি যথোপযুক্ত এবং অপ্রয়োজনীয়, কারণ আপনি উল্লেখ করেছেন যে এটি কঠোর সমতুল্য push_back(Type&& _Val)

তবে আসল সি ++ 0x ফর্ম emplace_back সত্যিই দরকারী: void emplace_back(Args&&...);

পরিবর্তে একটি গ্রহণ value_typeএটি আর্গুমেন্টগুলির একটি বৈচিত্রপূর্ণ তালিকা লাগে, যার অর্থ হল যে আপনি এখন আর্গুমেন্টগুলি পুরোপুরি ফরোয়ার্ড করতে পারবেন এবং কোনও অস্থায়ী ছাড়াই সরাসরি কোনও পাত্রে সরাসরি কোনও অবজেক্ট তৈরি করতে পারবেন।

এটি কার্যকর কারণ কারণ আরভিও এবং চালচলনের যেকোন চতুরতার বিষয়টি টেবিলের কাছে নিয়ে আসেনি এখনও জটিল জটিল পরিস্থিতি রয়েছে যেখানে ধাক্কা ব্যাক অপ্রয়োজনীয় অনুলিপিগুলি তৈরি করার সম্ভাবনা রয়েছে (বা সরানো)। উদাহরণস্বরূপ, এ এর ​​traditionalতিহ্যবাহী 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);

তাহলে কেন তারা এমএসভিসিতে এমপ্লে_ব্যাকের সঠিক সংস্করণটি প্রয়োগ করেনি? প্রকৃতপক্ষে, এটি আমাকে খুব আগেই বাগিয়ে দিয়েছে, তাই আমি ভিজ্যুয়াল সি ++ ব্লগে একই প্রশ্নটি জিজ্ঞাসা করেছি । মাইক্রোসফ্টে ভিজ্যুয়াল সি ++ স্ট্যান্ডার্ড লাইব্রেরি বাস্তবায়নের অফিসিয়াল রক্ষণাবেক্ষণকারী স্টিফান টি লাভভেজের উত্তর এখানে রয়েছে।

প্রশ্ন: বিটা 2 এম্প্লেস ফাংশনগুলি এখনই কেবল কোনও ধরণের স্থানধারক হিসাবে রয়েছে?

উত্তর: আপনারা জানেন যে, ভিসি 10 তে ভেরিয়াদিক টেম্পলেট প্রয়োগ করা হয় না। আমরা তাদের প্রিপ্রোসেসর make_shared<T>()মেশিনির মতো জিনিসগুলির মতো , টিপল এবং নতুন জিনিসগুলিতে সিমুলেট করি <functional> । এই প্রিপ্রসেসর যন্ত্রপাতিটি ব্যবহার ও রক্ষণাবেক্ষণ করা তুলনামূলকভাবে কঠিন। এছাড়াও, এটি সংকলনের গতিতে উল্লেখযোগ্যভাবে প্রভাব ফেলে, কারণ আমাদের বারবার সাবহেডারের অন্তর্ভুক্ত করতে হবে। আমাদের সময়ের সীমাবদ্ধতা এবং সংকলনের গতির উদ্বেগের সংমিশ্রণের কারণে আমরা আমাদের এম্বেস ফাংশনে ভেরিয়াদিক টেম্পলেটগুলি সিমুলেটেড করি না।

সংকলকটিতে যখন ভ্যারিয়্যাডিক টেম্পলেটগুলি প্রয়োগ করা হয়, আপনি আশা করতে পারেন যে আমরা আমাদের এমপ্লে ফাংশন সহ গ্রন্থাগারগুলিতে সেগুলি গ্রহণ করব। আমরা কনফারেন্সকে খুব গুরুত্ব সহকারে নিই, তবে দুর্ভাগ্যক্রমে, আমরা একবারে সব কিছু করতে পারি না।

এটি একটি বোধগম্য সিদ্ধান্ত। প্রিপ্রোসেসর ভয়ঙ্কর কৌশলগুলি সহ যে একবার মাত্র একবারে ভেরিয়ডিক টেম্পলেট অনুকরণ করার চেষ্টা করেছিল তারা জানে যে এই জিনিসটি কীভাবে ঘৃণ্য হয়।


100
এই স্পষ্টতা যে এটি একটি এমএসভিএস 10 সমস্যা, কোনও সি ++ ইস্যু নয় এটি এখানে সবচেয়ে গুরুত্বপূর্ণ অংশ। ধন্যবাদ।
me22

11
আমি বিশ্বাস করি আপনার সি ++ কোডের শেষ লাইনটি কাজ করবে না। pair<const int,Complicated>এমন কোনও কনস্ট্রাক্টর নেই যা কোনও ইনট, অন্য কোনও ইনট, একটি ডাবল এবং চতুর্থ পরামিতি হিসাবে স্ট্রিং নেয়। তবে আপনি সরাসরি এই জুটি অবজেক্টটি এর পিসওয়াস-কনস্ট্রাক্টর ব্যবহার করে তৈরি করতে পারেন । : সিনট্যাক্স ভিন্ন হবে, অবশ্যইm.emplace(std::piecewise,std::forward_as_tuple(4),std::forward_as_tuple(anInt,aDouble,aString));
sellibitze

3
সুখেরভাবে বৈকল্পিক টেম্পলেটগুলি এখন পূর্বরূপে, ভিএস ২০১৩ এ থাকবে।
ড্যানিয়েল আরউইকার

11
বনাম ২০১৩-এ নতুন পরিবর্তনগুলি প্রতিফলিত করতে এই উত্তরটি আপডেট করা উচিত?
বেকো

6
আপনি যদি ভিজ্যুয়াল স্টুডিও 2013 বা তার পরে এখন ব্যবহার করছেন তবে emplace_backভেরুডিক টেম্পলেটগুলি যুক্ত করার সময় ভিজ্যুয়াল সি ++ এ প্রয়োগ করা হলে আপনার "রিয়েল" এর পক্ষে সমর্থন থাকা উচিত : এমএসডিএন.মিকায়সফ্রোসফ
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 :: স্ট্রিং টাইপ করেছেন;
ডেভিড

4
@ ডেভিড: আমি নিশ্চিত নই যে পরবর্তী স্থান ছাড়া ধ্বংস ব্যতীত অন্য যে কোনও ব্যবহারের জন্য সরানো-থেকে থাকা অবজেক্টের বৈধ হওয়া দরকার।
বেন ভয়েগট

46
vec.emplace_back("Hello")কাজ করবে, যেহেতু const char*যুক্তিটি নির্মাণকারীর কাছে ফরোয়ার্ড করা হবে string। এটি পুরো পয়েন্ট emplace_back
আলেকজান্দ্রি সি

8
@ বেনভয়েগ্ট: একটি স্থানান্তরিত অবজেক্টের একটি বৈধ (তবে অনির্দিষ্ট) অবস্থায় থাকতে হবে। এর অর্থ এই নয় যে আপনি এটিতে কোনও অপারেশন করতে পারবেন can বিবেচনা করুন std::vector। খালিটি std::vectorএকটি বৈধ রাষ্ট্র, তবে আপনি front()এটিতে কল করতে পারবেন না । এর অর্থ হ'ল যে কোনও ক্রিয়াকলাপের পূর্ব শর্তাদি নেই তাকে এখনও বলা যেতে পারে (এবং ধ্বংসকারীদের কখনই পূর্বশর্ত থাকতে পারে না)।
ডেভিড স্টোন

94

এর জন্য অপ্টিমাইজেশন 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);যেখানে এক্স স্পষ্টভাবে মুভ-কনস্ট্রাকটেবল তবে কেবল স্পষ্টতই অনুলিপি-নির্মাণযোগ্য। emplace_back"অন্তর্নিহিত" স্পষ্টত সত্যটি আমাকে ভাবায় যে আমার সংযোজনের জন্য আমার যেতে ফাংশনটি সম্ভবত হওয়া উচিত push_back। থটস?
বেন

a.emplace_backদ্বিতীয়বার ফোন দিলে মুভ কনস্ট্রাক্টরকে ডাকা হবে!
এক্স Æ এ-12


8

emplace_backমানানসই বাস্তবায়ন vector<Object>::value_typeভেক্টরে যুক্ত হওয়ার পরে কনস্ট্রাক্টরের পক্ষে যুক্তি ফরোয়ার্ড করবে । আমি স্মরণ করি ভিজ্যুয়াল স্টুডিও ভ্যারোডিক টেম্পলেটগুলি সমর্থন করে নি, তবে ভেরুডিক টেমপ্লেটগুলির সাথে ভিজ্যুয়াল স্টুডিও 2013 আরসিতে সমর্থন করা হবে, সুতরাং আমি অনুমান করি যে একটি স্বাক্ষরকারী স্বাক্ষর যুক্ত হবে।

এর সাথে emplace_back, আপনি যদি সরাসরি যুক্তিগুলি vector<Object>::value_typeকন্সট্রাক্টরের কাছে ফরোয়ার্ড করেন তবে emplace_backকঠোরভাবে কথা বলার জন্য আপনাকে ফাংশনের জন্য অস্থাবর বা অনুলিপিযোগ্য হওয়ার জন্য কোনও ধরণের প্রয়োজন নেই । ইন vector<NonCopyableNonMovableObject>কেস, এই যেহেতু দরকারী নয়, vector<Object>::value_type একটি copyable বা অস্থাবর টাইপ হত্তয়া প্রয়োজন।

তবে মনে রাখবেন যে এটি আপনার জন্য কার্যকর হতে পারে std::map<Key, NonCopyableNonMovableObject>, যেহেতু একবার আপনি মানচিত্রে কোনও এন্ট্রি বরাদ্দ করেন, এটি আর সরানো বা অনুলিপি করার দরকার নেই, এর বিপরীতে নয় vector, যার অর্থ আপনি std::mapকোনও ম্যাপযুক্ত প্রকারের সাথে কার্যকরভাবে ব্যবহার করতে পারবেন যা অনুলিপিযোগ্যও নয় nor অস্থাবর।



1

সুনির্দিষ্ট ব্যবহারের ক্ষেত্রে emplace_back: আপনার যদি একটি অস্থায়ী বস্তু তৈরি করতে হয় যা একটি ধারক মধ্যে ঠেলাঠেলি করা হয়, emplace_backপরিবর্তে ব্যবহার করুন push_back। এটি ধারকটির অভ্যন্তরে স্থানটি তৈরি করবে।

মন্তব্য:

  1. push_backউপরের ক্ষেত্রে একটি অস্থায়ী অবজেক্ট তৈরি করে এটি পাত্রে স্থানান্তরিত করবে। তবে, জন্য ব্যবহৃত জায়গার emplace_backনির্মাণটি নির্মাণ এবং তারপরে বস্তুটি সরানোর চেয়ে আরও পারফরম্যান্স হবে (যার মধ্যে সাধারণত কিছু অনুলিপি জড়িত)।
  2. সাধারণভাবে, আপনি খুব বেশি সমস্যা ছাড়াই সব ক্ষেত্রে emplace_backপরিবর্তে ব্যবহার করতে পারেন push_back। ( ব্যতিক্রম দেখুন )
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.