2013-02-11 28 views
25

sorun haline nesneyi taşıma dev objeler Bir hamle garanti edemez nasıl haritalar bir harita ile bu

Huge huge1(some,args); 
Huge huge2(some,args); 

std::map<int,Huge> map1; 
std::map<Huge,int> map2; 

map1.insert({0,huge1}); 
map2.insert({huge2,0}); 

kopyalanacak bu? Bu işe yarayacak mı yoksa daha mı var?

std::pair<iterator,bool> insert(value_type&&);

R-değeri kurucular açılmasına neden olur, bu aşırı bağlanan herhangi bir ifade:

map1.insert({0,std::move(huge1)}); 
map2.insert({std::move(huge2),0}); 
+1

Tam olarak bunu birkaç gün önce sordum: http://stackoverflow.com/questions/14581414/insert-map-entry-by-r-value-moving-of-mapped-type – Chowlett

+0

Tam olarak aynı şey değil, @Chowlett. – Yakk

+0

@Yakk - ... çünkü anahtar-tipi de kopyalanabildiğinden emin olmak için gereken hareket için kullanılabilir mi? Yoksa başka bir şey mi özlüyorum? – Chowlett

cevap

37

std::map::insert R-değerlerinin için bir aşırı sahiptir. std::map<K,V>::value_typestd::pair<const key_type, mapped_type> ve std::pair R değerleri alan bir kurucu sahip olduğu: pair nesnenin oluşturulması, her ikisi de

template<class U1, class U2> 
pair(U1&& x, U2&& y); 
sonra

Eğer key_type ve mapped_type için R-değeri kurucular çağrılabilen olduğunu garanti edilmiştir ve harita yerleştirilmesi sırasında, sürece örneğin R-değerleri, yaratan bir ifade kullanılarak çift yerleştirirken:

map1.insert(std::make_pair(0, Huge()); 

TD

map1.insert(std::make_pair(0, std::move(huge1)); 
sadece bir öğesi olarak yeni Huge nesneyi oluşturmak istiyorsanız Nihayet

Huge(Huge&& h) 
{ 
    ... 
} 


, ayrıca std::map::emplace kullanabilirsiniz: Elbette

, bütün bunlar Huge uygun bir R-değeri yapıcı olmasına bağlıdır haritada.

+1

Aynı zamanda brace başlatıcısı ile kullandığı örneğin de çalıştığını da eklerim. Ayrıca, çift yapıcı aslında bir evrensel referans yapıcıdır, çünkü argümanların tümü/hiçbiri r-değeri olmayabilir ve yine de seçilecektir. Bunu bir r-değerli kurucu olarak adlandırmak, insanları her iki argümanın r-değeri olarak düşünmesi konusunda kafa karıştırıcı olabilir, ki bu doğru değildir. – mmocny

14

Bunu yapabilirsiniz ({0,std::move(huge1)} parçası). Fonksiyonun nesneleri verilirse

map1.emplace(std::piecewise_construct, 0, std::forward_as_tuple(some, args)); 
map2.emplace(std::piecewise_construct, std::forward_as_tuple(some, args), 0); 

Ya da, yine de kullanabilirsiniz emplace:

map1.emplace(0, std::move(huge1)); 
map2.emplace(std::move(huge1), 0); 
Ama aynı zamanda böyle aracıyı (işlevi içinde nesneleri inşa ediyoruz varsayılarak) atlayabiliriz
6

Kopyalama ve hareket etmeyi önleyen bir alternatif std::map::emplace() kullanmak olacaktır. Bağlantılı başvuru sayfasından:

Konteynere yeni bir eleman ekler. Öğe yerinde oluşturulmuştur, yani hiçbir kopya veya taşıma işlemi gerçekleştirilmez., işleve sağlanan std ileri (prmtr) :: ile iletilen tam olarak aynı argümanlar çağrılır eleman türü (VALUE_TYPE, yani std :: çifti) yapıcısı ....

2

Yukarıdakilerle birlikte, std::unique_ptr<>'un bir kopyalama kurucusunun eksikliğine de güvenebilirsiniz, ancak bu durum ara yüzünü biraz değiştirir.Beklenen çıktı üretir

#include <iostream> 
#include <map> 
#include <memory> 

class Huge { 
public: 
    Huge(int i) : x{i} {} 
    int x; 
}; 

using HugePtrT = std::unique_ptr<Huge>; 
using MyMapT = std::map<int, HugePtrT>; 


int 
main() { 
    MyMapT myMap; 
    myMap[42].reset(new Huge{1}); 
    std::cout << myMap[42]->x << std::endl; 
    myMap[43] = std::move(myMap[42]); 
    if (myMap[42]) 
    std::cout << "42: " << myMap[42]->x << std::endl; 
    if (myMap[43]) 
    std::cout << "43: " << myMap[43]->x << std::endl; 
} 

: Eğer std::move() çağrıyı atlarsanız

1 
43: 1 

program derlemek için başarısız olur. Benzer şekilde, işaretçiyi atamak için .reset()'u kullanabilirsiniz.

Bu, R değeri taşıyan bir kurucunun bulunmadığı, çok hafif olduğu, bellek sahipliğinin açıkça tanımlandığı ve boost::optional<> benzeri semantiklere sahip sınıflar üzerinde çalışmasının avantajına sahiptir. std::unique_ptr'un bir R-Değeri yapıcısı tarafından taşınan bir nesneden daha hafif olduğu konusunda bir argüman yapılabilir. Çünkü bir R-Değeri taşınan nesne bir ayırma gerektirir (ancak adil olmak gerekirse, tüm C++ 11 derleyicileri) Nesnenin bağırsakları taşınsa bile, destek Dönüş Değeri Optimizasyonları veya kopyalama seçiminin farkında olun).

std::unique_ptr<>, bunun gibi çalışır çünkü std::unique_ptr<>'un bir kopya yapıcısı yok, yalnızca bir hamleyi yapıcıya sahip.

İlgili konular