Zaten oluşturulmuş nesneler için std :: move ile emplace_back () arasında C ++ 11 push_back () verimliliği


88

C ++ 11'de emplace_back(), push_back()yerinde yapılanmaya izin verdiği için genellikle (verimlilik açısından) tercih edilir , ancak bu push_back(std::move()), önceden oluşturulmuş bir nesne ile kullanıldığında hala geçerli midir?

Örneğin emplace_back(), aşağıdaki gibi durumlarda hala tercih ediliyor mu?

Ek olarak, yukarıdaki örnekte aşağıdakileri yapmanın herhangi bir faydası var mı?

yoksa buradaki hareket tamamen gereksiz mi, yoksa hiçbir etkisi yok mu?


myvector.emplace_back(mystring);kopyalar ve hareket etmez. Diğer iki hareket ve eşdeğer olmalıdır.
TC

Yanıtlar:


117

Sağladığınız farklı çağrıların ne işe yaradığını görelim:

  1. emplace_back(mystring): Bu, sağladığınız bağımsız değişkenle birlikte yeni öğenin yerinde yapılanmasıdır. Bir değer sağladığınız için, bu yerinde inşa aslında bir kopya-yapımdır, yani bu, çağırmakla aynıdırpush_back(mystring)

  2. push_back(std::move(mystring)): Bu, std::stringyerinde bir hareket konstrüksiyonu olması durumunda hareket yerleştirmeyi çağırır .

  3. emplace_back(std::move(mystring)): Bu yine sağladığınız argümanlarla yerinde bir yapıdır. Bu argüman bir rvalue olduğu için, move-yapıcısını çağırır std::string, yani 2'deki gibi yerinde bir hareket-inşasıdır.

Başka bir deyişle, T türünde bir bağımsız değişkenle çağrılırsa, bu bir rvalue veya lvalue olsun emplace_backve push_backeşdeğerdir.

Bununla birlikte, diğer herhangi bir argüman emplace_backiçin yarışı kazanır, örneğin a char const*in a ile vector<string>:

  1. emplace_back("foo")çağrıları std::string(char const*)in-yer-inşaat için.

  2. push_back("foo")önce std::string(char const*)işlevin imzasıyla eşleşmesi için gereken örtük dönüşümü ve ardından yukarıdaki durum 2. gibi bir hareket ekleme çağırmalıdır . Bu nedenle eşdeğerdirpush_back(string("foo"))


1
Taşıma yapıcısı genellikle kopya oluşturuculardan daha etkilidir, bu nedenle rvalue (durum 2, 3) kullanmak, aynı anlambilime rağmen bir lvalue (durum 1) kullanmaktan daha etkilidir.
Ryan Li

peki ya böyle bir durum? void foo (string && s) {vector.emplace (s); // 1 vector.emplace (std :: move (s)); // 2}
VALOD9

@VALOD bunlar yine listemin 1 ve 3 numaraları. srvalue bağlar sadece SağDeğerler referansla, ancak iç olarak tanımlanabilir foo, sbir lvalue olup.
Arne Mertz

1

Emplace_back, rvalue referanslarının bir listesini alır ve doğrudan yerinde bir konteyner öğesi oluşturmaya çalışır. Emplace_back'i, konteyner eleman kurucularının desteklediği tüm türlerle çağırabilirsiniz. Rvalue referansları olmayan parametreler için emplace_back çağrıldığında, normal referanslara 'geri döner' ve en azından kopya yapıcı, parametre ve konteyner elemanları aynı tipte olduğunda çağrılır. Sizin durumunuzda, 'myvector.emplace_back (mystring)' dizenin bir kopyasını yapmalıdır çünkü derleyici myvector parametresinin taşınabilir olduğunu bilemez. Öyleyse std :: move'ı ekleyin, size istenen faydayı sağlar. Push_back, önceden oluşturulmuş elemanlar için emplace_back kadar çalışmalıdır.


2
Bu ... iletme / evrensel referansları tanımlamanın ilginç bir yolu.
TC
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.