2012-12-28 14 views
7

Bir STL kapsayıcıyı kapsayıcının bir kopyasını mı yoksa başka bir takma ad mı ilettiğini hatırlayamıyorum. Bir kaç konteyner varsa:STL Konteynerlerini Geçmek Bir Kopyalama Yapıyor mu?

std::unordered_map<int,std::string> _hashStuff; 
std::vector<char> _characterStuff; 

Ve ben bir işleve bu değişkenleri geçmek istiyorum, ben şekilde işlev yapabilir:

void SomeClass::someFunction(std::vector<char> characterStuff); 

Ya da bu unordered_map bir kopyasını yapacak/vector? Sanırım shared_ptr'u kullanmam gerekebilir.

void SomeClass::someFunction(std::shared_ptr<std::vector<char>> characterStuff); 
+0

Tek kolonlarınız ':' çift kolonlu olmamalıdır '::'? – 0x499602D2

+0

@David evet, çift colons olmalıdırlar :: :: –

+0

Kopya geçişini referans olarak önlemek için (tercihen const reference). –

cevap

7

Bu, bağlıdır. İşlevinize bir lvalue aktarıyorsanız (pratikte, bir adı olan ve bir kullanıcı adıyla & adresinin uygulanabileceği bir ad gönderiyorsanız), sınıfınızın kopya kurucusu çağrılır.

void foo(vector<char> v) 
{ 
    ... 
} 

int bar() 
{ 
    vector<char> myChars = { 'a', 'b', 'c' }; 
    foo(myChars); // myChars gets COPIED 
} 

sen ve sınıf bir hareket Oluşturucu sahip, daha sonra nesneyi (bir isim ve adres-operatörü & tatbik edilemeyen zorunda değildir kabaca, bir şey) bir rvalue geçiyoruz hareket ettirilecek (bu, dikkat etmeyin, bir "takma ad" oluşturmakla aynıdır, aksine nesnenin bağırsaklarını yeni bir iskelete aktararak, önceki iskeleti işe yaramaz hale getirir). foo() çağırma olarak

altında make_vector() sonucu, bir rvalue olup.

void foo(vector<char> v); 
{ 
    ... 
} 

vector<char> make_vector() 
{ 
    ... 
}; 

int bar() 
{ 
    foo(make_vector()); // myChars gets MOVED 
} 

Bazı STL sınıfları bir hareket yapıcısı var ama bir kopyası yok: Bu nedenle, döner nesne (yani vector 'ın hareket yapıcı çağrılır) foo() için girişte verildiğinde taşındıktan olduğunu Oluşturucu, çünkü bunlar doğal olarak gömülebilir olmamalıdır (örneğin, unique_ptr). Bir işleve ilettiğinizde unique_ptr kopyasını almayacaksınız.

Bir kopya oluşturucuya sahip olan sınıflar için bile, argümanınızı bir değerden bir değere dönüştürmek için std::move işlevini kullanarak semantiği hareket ettirmeye zorlayabilirsiniz, ancak yine de bu bir takma oluşturmaz, yalnızca aktarır Nesnenin sahipliğini, çağırmakta olduğunuz işleve. Bu, başka bir değere yeniden tahsis etmekten veya onu yok etmekten başka, orijinal nesneyle başka hiçbir şey yapamayacağınız anlamına gelir. Örneğin

: Eğer lvalue ve rvalue referansların bütün bu konuyu bulup karanlık semantiğini taşırsanız

void foo(vector<char> v) 
{ 
    ... 
} 

vector<char> make_vector() 
{ 
    ... 
}; 

int bar() 
{ 
    vector<char> myChars = { 'a', 'b', 'c' }; 
    foo(move(myChars)); // myChars gets MOVED 
    cout << myChars.size(); // ERROR! object myChars has been moved 
    myChars = make_vector(); // OK, you can assign another vector to myChars 
} 

, bu çok anlaşılır bir durum.

http://thbecker.net/articles/rvalue_references/section_01.html

Ayrıca http://www.isocpp.org veya YouTube'a (Scott Meyers tarafından seminer arayın) biraz bilgi bulmak mümkün olmalıdır: Ben şahsen oldukça yararlı bu öğretici buldum.

+1

Buradaki bütün cevaplar cevap olarak işaretlenecek kadar doğru düşünürsem de, en ilgi çekici olanını buldum. –

+0

Teşekkürler! Her neyse, iyi bir malzemeyi okuduktan sonra bu şeyi kavramanın en iyi yolu, onunla biraz oynamaya çalışmaktır. Bir hamle yapıcısı ve bir kopya kurucusu ile küçük bir oyuncak sınıfı yazmanızı, bazı işlevlere değere göre aktarmanızı ve hangisinin çağrıldığını görmenizi öneririm (hata ayıklama yoluyla veya bazı "cout << msg" ifadelerini yerleştirerek). Ayrıca, yukarıdaki 'make_vector() 'dan dönerken olduğu gibi, bazen hiçbir kurucunun hiç kullanılmadığını fark edeceksiniz: bu, genellikle bir optimizasyon derleyicisidir. –

5

Evet, vektöre değer aktardığınız için kopyalanır. Değere göre geçmek her zaman bir kopyasını veya hareketini yapar (belirli koşullar altında seçilebilir, fakat sizin durumunuzda olmayabilir). Fonksiyonun dışında aynı vektöre başvurmak isterseniz, bunun yerine referans olarak iletebilirsiniz.

void SomeClass::someFunction(std::vector<char>& characterStuff); 

tip std::vector<char>& bir başvuru türü "referans std::vector<char> için" dir: için işlevini değiştirin. characterStuff adı, _characterStuff tarafından belirtilen nesne için bir takma ad olarak davranacaktır.

+0

Nitpick: Değere göre geçiş yapmayı * düşünmüyorum * her zaman bir kopya yapar. Örneğin, geçici bir değere geçerken, derleyicinin kopyayı eline almasına izin verdiğinden oldukça eminim. –

+0

@ BjörnPollex Evet! Bundan bahsetmeyi unuttum. –

4

C++ değerleri temel alır: Nesneye göre değer aktarırken bağımsız kopyalar alırsınız. Çağrılan işlev argüman değiştirmek mümkün olmamalıdır zaman

void SomeClass::someFunction(std::vector<char>& changable) { ... } 
void SomeClass::otherFunction(std::vector<char> const& immutable) { ... } 

ama istemiyorum: Bir kopyasını almak istemiyorsanız, bunun yerine bir başvuru ya da const başvuru kullanabilirsiniz Nesnenin bir kopyasını oluşturmak, const& ile geçmek istersiniz. Normalde, bunun yerine std::shared_ptr<T> gibi bir şey kullanmazdım. Bir işlevi çağırırken kopyalamayı kesinlikle engellememek için bu türden kullanımlar vardır.

İlgili konular