Hareket semantiği, bir değeri döndürürken bir o kadar büyük bir gelişme olmayabilir - ve bir shared_ptr
(veya benzer bir şey) kullandığınızda / kullandığınızda , muhtemelen erken kararlaştırırsınız. Gerçekte, neredeyse tüm makul modern derleyiciler Dönüş Değeri Optimizasyonu (RVO) ve Adlandırılmış Dönüş Değeri Optimizasyonu (NRVO) olarak adlandırılanları yapar. Bu araçlar Bir değer döndüren yerine aslında değerini kopyalayarak yaparken o hiç, yalnızca dönüşten sonra değerin atanacağı yere gizli bir işaretçi / referans iletirler ve işlev, sonuna kadar değer oluşturmak için bunu kullanır. C ++ standardı buna izin vermek için özel hükümler içerir, bu nedenle (örneğin) kopya kurucunuzun görünür yan etkileri olsa bile, değeri döndürmek için kopya kurucusunu kullanmanız gerekmez. Örneğin:
#include <vector>
#include <numeric>
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <iterator>
class X {
std::vector<int> a;
public:
X() {
std::generate_n(std::back_inserter(a), 32767, ::rand);
}
X(X const &x) {
a = x.a;
std::cout << "Copy ctor invoked\n";
}
int sum() { return std::accumulate(a.begin(), a.end(), 0); }
};
X func() {
return X();
}
int main() {
X x = func();
std::cout << "sum = " << x.sum();
return 0;
};
Buradaki temel fikir oldukça basittir: Mümkünse kopyalamaktan kaçınmak için yeterli içeriğe sahip bir sınıf oluşturun ( std::vector
32767 rastgele ints ile dolduruyoruz). Ne zaman kopyalanıp kopyalanmayacağını bize gösteren açık bir kopyalayıcıya sahibiz. Ayrıca, nesnede rastgele değerlerle bir şeyler yapmak için biraz daha kodumuz var, bu nedenle optimizer, hiçbir şey yapmadığı için sınıfla ilgili her şeyi (en azından kolayca) ortadan kaldırmayacak.
Daha sonra, bu nesnelerden birini bir işlevden döndürmek için bazı kodlarımız var ve daha sonra, nesnenin gerçekten tamamen yok sayılmakla kalmayıp, gerçekten oluşturulduğundan emin olmak için toplamı kullanıyoruz. Bunu çalıştırdığımızda, en azından en yeni / modern derleyicilerle, yazdığımız kopya yapıcısının hiç bir zaman çalışmadığını görüyoruz - ve evet, a ile hızlı bir kopyanın bile kopyalama yapmaktan shared_ptr
daha yavaş olduğundan eminim hiç.
Taşınma, onlar olmadan (doğrudan) yapamayacağınız çok sayıda şeyi yapmanızı sağlar. Harici bir birleştirme türünün "birleştirme" bölümünü düşünün; örneğin, birleştireceğiniz 8 dosyanız vardır. İdeal olarak, bu dosyaların 8 tanesini bir vector
- içine koymak istersiniz, ancak vector
(C ++ 03 itibarıyla) öğeleri kopyalayabilmesi ifstream
gerektiğinden ve kopyalanamayacağı için bazı unique_ptr
/ shared_ptr
, veya bunları bir vektöre koyabilmek için bu düzende bir şey. Not bile biz (örneğin) eğer reserve
uzayda vector
emin bizim ediyoruz böylece ifstream
kod rağmen derlemek olmayacak şekilde, s gerçekten kopyalanmış asla, derleyici bunu bilmeyecek biz kopya yapıcı asla biliyorum yine de kullanılır.
Hala kopyalanamaz bile, C ++ 11 bir ifstream
olabilir taşınacak. Bu durumda, nesneler muhtemelen olmaz hiç taşınacak, ama bizim koymak, böylece gerekirse olabilecekleri gerçeği, derleyici mutlu ediyor ifstream
bir nesne vector
doğrudan herhangi akıllı işaretçi hacks.
Bir vektör yapar genişletmek hareket semantik gerçekten olabileceğini bir zamanın oldukça iyi bir örnektir / kullanışlı olsa vardır. Bu durumda, RVO / NRVO yardımcı olmaz, çünkü bir işlevden (veya çok benzer bir şeyden) dönüş değeri ile ilgilenmiyoruz. Bazı nesneleri tutan bir vektörünüz var ve bu nesneleri yeni, daha büyük bir bellek yığınına taşımak istiyoruz.
C ++ 03'te bu, yeni bellekteki nesnelerin kopyalarını oluşturarak ve ardından eski bellekteki eski nesneleri yok ederek yapılır. Ancak tüm bu kopyaları eskilerini atmak için yapmak oldukça zaman kaybıydı. C ++ 11'de, bunun yerine taşınmasını bekleyebilirsiniz. Bu genellikle özünde, (genellikle çok daha yavaş) derin bir kopya yerine sığ bir kopya yapmamızı sağlar. Başka bir deyişle, bir dize veya vektörle (yalnızca birkaç örnek için), işaretçilerin başvurduğu tüm verilerin kopyalarını yapmak yerine yalnızca işaretçiyi / nesneleri nesnelere kopyalarız.
shared_ptr
sadece hızlı kopyalama uğruna sakının ) ve eğer hareket semantiği neredeyse hiç kodlama, anlambilim ve temizlik cezası olmadan bunu başarabilirse.