Saya mengetahui 5 kategori umum di mana mengkompilasi ulang kompiler C ++ 03 karena C ++ 11 dapat menyebabkan peningkatan kinerja tanpa batas yang secara praktis tidak terkait dengan kualitas implementasi. Ini semua adalah variasi dari semantik gerakan.
std::vector
realokasi
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
setiap kali foo
buffer dialokasikan kembali dalam C ++ 03 itu disalin setiap vector
dalam bar
.
Dalam C ++ 11 ia malah memindahkan bar::data
s, yang pada dasarnya gratis.
Dalam hal ini, ini bergantung pada optimasi di dalam std
wadah vector
. Dalam setiap kasus di bawah ini, penggunaan std
kontainer hanya karena mereka adalah objek C ++ yang memiliki move
semantik efisien dalam C ++ 11 "secara otomatis" ketika Anda meningkatkan kompiler Anda. Objek yang tidak memblokirnya yang berisi std
wadah juga mewarisi move
konstruktor yang ditingkatkan secara otomatis .
Kegagalan NRVO
Ketika NRVO (bernama optimisasi nilai balik) gagal, dalam C ++ 03 jatuh kembali pada salinan, pada C ++ 11 jatuh kembali bergerak. Kegagalan NRVO mudah:
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;
}
atau bahkan:
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;
}
Kami memiliki tiga nilai - nilai kembali, dan dua nilai berbeda dalam fungsi. Elision memungkinkan nilai-nilai dalam fungsi untuk 'digabung' dengan nilai kembali, tetapi tidak dengan satu sama lain. Keduanya tidak dapat digabungkan dengan nilai pengembalian tanpa bergabung satu sama lain.
Masalah mendasarnya adalah bahwa NRVO elision rapuh, dan kode dengan perubahan tidak di dekat return
situs tiba-tiba dapat memiliki pengurangan kinerja besar-besaran di tempat itu tanpa diagnostik yang dikeluarkan. Dalam kebanyakan kasus kegagalan NRVO C ++ 11 berakhir dengan a move
, sedangkan C ++ 03 berakhir dengan salinan.
Mengembalikan argumen fungsi
Penghilangan juga tidak mungkin di sini:
std::set<int> func(std::set<int> in){
return in;
}
di C ++ 11 ini murah: di C ++ 03 tidak ada cara untuk menghindari salinan. Argumen untuk fungsi tidak dapat dielakkan dengan nilai kembali, karena masa pakai dan lokasi parameter dan nilai kembali dikelola oleh kode panggilan.
Namun, C ++ 11 dapat berpindah dari satu ke yang lain. (Dalam contoh mainan yang kurang, sesuatu mungkin dilakukan untuk set
).
push_back
atau insert
Akhirnya, elisi ke dalam wadah tidak terjadi: tetapi C ++ 11 membebani secara berlebihan nilai memindahkan operator insert, yang menyimpan salinan.
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) );
di C ++ 03 whatever
dibuat sementara , kemudian disalin ke dalam vektor v
. 2 std::string
buffer dialokasikan, masing-masing dengan data yang identik, dan satu dibuang.
Dalam C ++ 11 sementara whatever
dibuat. The whatever&&
push_back
berlebihan maka move
s yang sementara ke vektor v
. Satu std::string
buffer dialokasikan, dan dipindahkan ke vektor. Sebuah kosong std::string
dibuang.
Tugas
Dicuri dari jawaban @ Jarod42 di bawah ini.
Elision tidak dapat terjadi dengan penugasan, tetapi pindah-dari bisa.
std::set<int> some_function();
std::set<int> some_value;
// code
some_value = some_function();
di sini some_function
mengembalikan kandidat untuk dielakkan, tetapi karena tidak digunakan untuk membangun objek secara langsung, itu tidak dapat dielakkan. Dalam C ++ 03, hasil di atas dalam konten sementara disalin ke some_value
. Di C ++ 11, ia dipindahkan ke some_value
, yang pada dasarnya gratis.
Untuk efek penuh dari hal di atas, Anda memerlukan kompiler yang mensintesis pemindahan konstruktor dan tugas untuk Anda.
MSVC 2013 mengimplementasikan gerakan konstruktor dalam std
wadah, tetapi tidak mensintesis gerakan konstruktor pada tipe Anda.
Jadi tipe yang mengandung std::vector
dan sejenisnya tidak mendapatkan peningkatan seperti itu di MSVC2013, tetapi akan mulai mendapatkannya di MSVC2015.
dentang dan gcc telah lama diimplementasikan konstruktor bergerak implisit. Kompiler Intel 2013 akan mendukung pembuatan konstruktor pemindahan implisit jika Anda lulus -Qoption,cpp,--gen_move_operations
(mereka tidak melakukannya secara default dalam upaya untuk kompatibel dengan MSVC2013).