C ++ 11 derleyicisini yeniden derlemenin, C ++ 11'in uygulama kalitesi ile neredeyse ilgisiz olan sınırsız performans artışlarına neden olabileceği 5 genel kategorinin farkındayım. Bunlar hareket semantiğinin çeşitleridir.
std::vector
yeniden tahsis
struct bar{
std::vector<int> data;
};
std::vector<bar> foo(1);
foo.back().data.push_back(3);
foo.reserve(10); // two allocations and a delete occur in C++03
Her seferinde foo
'ın tampon 03 C ++ yeniden tahsis edilmektedir her kopyalanan vector
içinde bar
.
C ++ 11'de bunun yerine bar::data
temelde ücretsiz olan s'yi taşır .
Bu durumda, bu std
konteyner içindeki optimizasyonlara dayanır vector
. Aşağıdaki her durumda, std
kapsayıcıların kullanımı, move
derleyicinizi yükselttiğinizde C ++ 11'de "otomatik olarak" etkin semantiğe sahip C ++ nesneleri oldukları içindir . Bir std
kap içeren onu engellemeyen nesneler de otomatik geliştirilmiş move
yapıcıları devralır .
NRVO hatası
NRVO (adlandırılmış dönüş değeri optimizasyonu) başarısız olduğunda, C ++ 03'te kopyaya geri döner, C ++ 11'de tekrar harekete geçer. NRVO'nun arızaları kolaydır:
std::vector<int> foo(int count){
std::vector<int> v; // oops
if (count<=0) return std::vector<int>();
v.reserve(count);
for(int i=0;i<count;++i)
v.push_back(i);
return v;
}
ya da:
std::vector<int> foo(bool which) {
std::vector<int> a, b;
// do work, filling a and b, using the other for calculations
if (which)
return a;
else
return b;
}
Üç değerimiz var - dönüş değeri ve işlev içinde iki farklı değer. Elision, fonksiyon içindeki değerlerin dönüş değeriyle 'birleştirilmesine' izin verir, ancak birbiriyle birleştirilmesine izin verir. Her ikisi de birbirleriyle birleşmeden dönüş değeri ile birleştirilemez.
Temel sorun, NRVO elüsyonunun kırılgan olması ve return
sitenin yakınında olmayan değişikliklere sahip kodun , herhangi bir tanı yayılmadan aniden büyük performans düşüşlerine sahip olabilmesidir. Çoğu NRVO başarısızlık durumunda C ++ 11 a ile move
, C ++ 03 ise bir kopya ile sonlanır.
İşlev bağımsız değişkenini döndürme
Burada seçim yapmak da imkansız:
std::set<int> func(std::set<int> in){
return in;
}
C ++ 11 bu ucuz: C ++ 03 kopyasını önlemek için hiçbir yolu yoktur. Parametrelerin ve dönüş değerinin ömrü ve konumu, arama kodu tarafından yönetildiği için işlevlere ilişkin bağımsız değişkenler döndürülemez.
Ancak, C ++ 11 birinden diğerine geçebilir. (Daha az oyuncak örneğinde, için bir şey yapılabilir set
).
push_back
veya insert
Son olarak kaplara eleme gerçekleşmez: ancak C ++ 11, kopyaları kaydeden rvalue move insert operatörlerini aşırı yükler.
struct whatever {
std::string data;
int count;
whatever( std::string d, int c ):data(d), count(c) {}
};
std::vector<whatever> v;
v.push_back( whatever("some long string goes here", 3) );
C ++ 03'te bir geçici whatever
oluşturulur, daha sonra vektöre kopyalanır v
. std::string
Her biri aynı veriye sahip 2 tampon ayrılır ve biri atılır.
C ++ 11'de geçici whatever
oluşturulur. whatever&&
push_back
Aşırı sonra move
vektör içine geçici s v
. Bir std::string
tampon tahsis edilir ve vektöre taşınır. Boş std::string
bir atılır.
Görev
@ Jarod42'nin aşağıdaki cevabından çalındı.
Seçim atama ile gerçekleşemez, ancak geçiş yapılabilir.
std::set<int> some_function();
std::set<int> some_value;
// code
some_value = some_function();
burada some_function
bir adayı elide olarak döndürür, ancak doğrudan bir nesne inşa etmek için kullanılmadığından, seçilemez. C ++ 03'te, yukarıdaki geçici kopyaya kopyalanır some_value
. C ++ 11'de, some_value
temelde ücretsiz olan içine taşınır .
Yukarıdakilerin tam etkisi için, hareket yapıcılarını ve atamayı sizin için sentezleyen bir derleyiciye ihtiyacınız vardır.
MSVC 2013, hareket yapıcılarını std
kaplarda uygular , ancak hareket yapıcılarını türleriniz üzerinde sentezlemez.
Bu nedenle, std::vector
s ve benzerlerini içeren türler MSVC2013'te bu tür iyileştirmeler elde etmez, ancak MSVC2015'te almaya başlayacaktır.
clang ve gcc uzun zamandan beri örtük hareket yapıcıları uygulamaktadır. Intel'in 2013 derleyicisi, geçerseniz örtük nesil oluşturucuları destekleyecektir -Qoption,cpp,--gen_move_operations
(MSVC2013 ile çapraz uyumlu olma çabasıyla bunu varsayılan olarak yapmazlar).