Dalam C ++ 11 emplace_back()
umumnya lebih disukai (dalam hal efisiensi) push_back()
daripada karena memungkinkan konstruksi di tempat, tetapi apakah ini masih terjadi saat menggunakan push_back(std::move())
dengan objek yang sudah dibangun?
Misalnya, apakah emplace_back()
masih disukai dalam kasus seperti berikut ini?
std::string mystring("hello world");
std::vector<std::string> myvector;
myvector.emplace_back(mystring);
myvector.push_back(std::move(mystring));
// (of course assuming we don't care about using the value of mystring after)
Selain itu, apakah ada manfaat dalam contoh di atas untuk melakukan:
myvector.emplace_back(std::move(mystring));
atau apakah perpindahan ke sini sepenuhnya mubazir, atau tidak berpengaruh?
c++11
move-semantics
push-back
emplace
Kerusuhan
sumber
sumber
myvector.emplace_back(mystring);
menyalin dan tidak bergerak. Dua gerakan lainnya dan harus setara.Jawaban:
Mari kita lihat fungsi dari berbagai panggilan yang Anda berikan:
emplace_back(mystring)
: Ini adalah konstruksi elemen baru di tempat dengan argumen apa pun yang Anda berikan. Karena Anda memberikan nilai l, konstruksi di tempat itu sebenarnya adalah konstruksi salinan, yaitu sama dengan memanggilpush_back(mystring)
push_back(std::move(mystring))
: Ini memanggil penyisipan-pindah, yang dalam kasusstd::string
ini adalah konstruksi-perpindahan di tempat.emplace_back(std::move(mystring))
: Sekali lagi ini adalah konstruksi di tempat dengan argumen yang Anda berikan. Karena argumen itu adalah nilai r, ia memanggil konstruktor-perpindahanstd::string
, yaitu, konstruksi-perpindahan di tempat seperti pada 2.Dengan kata lain, jika dipanggil dengan satu argumen tipe T, baik itu nilai r atau nilai l,
emplace_back
danpush_back
ekuivalen.Namun, untuk argumen lainnya,
emplace_back
memenangkan perlombaan, misalnya denganchar const*
dalamvector<string>
:emplace_back("foo")
panggilanstd::string(char const*)
untuk konstruksi di tempat.push_back("foo")
pertama-tama harus memanggilstd::string(char const*)
konversi implisit yang diperlukan untuk mencocokkan tanda tangan fungsi, lalu pindah-penyisipan seperti kasus 2. di atas. Oleh karena itu, ini setara denganpush_back(string("foo"))
sumber
s
dapat didefinisikan sebagai rujukan nilai r yang mengikat hanya ke rvalues, tetapi di dalamfoo
,s
adalah nilai l.Emplace_back mendapatkan daftar referensi nilai r dan mencoba membangun elemen kontainer langsung di tempatnya. Anda dapat memanggil emplace_back dengan semua jenis yang didukung oleh konstruktor elemen kontainer. Ketika memanggil emplace_back untuk parameter yang bukan referensi rvalue, ia 'kembali' ke referensi normal dan setidaknya konstruktor salinan dipanggil ketika parameter dan elemen wadah memiliki tipe yang sama. Dalam kasus Anda 'myvector.emplace_back (mystring)' harus membuat salinan dari string karena kompiler tidak dapat mengetahui bahwa parameter myvector dapat dipindahkan. Jadi masukkan std :: move apa yang memberi Anda keuntungan yang diinginkan. Push_back harus bekerja sebaik emplace_back untuk elemen yang sudah dibangun.
sumber