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.