Dengan standar baru, ada cara-cara baru dalam melakukan sesuatu, dan banyak yang lebih baik daripada cara-cara lama, tetapi cara lama masih baik-baik saja. Juga jelas bahwa standar baru tidak secara resmi mencela, karena alasan kompatibilitas. Jadi pertanyaan yang tersisa adalah:
Apa cara pengkodean lama yang jelas lebih rendah dari gaya C ++ 11, dan apa yang bisa kita lakukan sekarang?
Dalam menjawab ini, Anda dapat melewati hal-hal yang jelas seperti "gunakan variabel otomatis".
auto_ptr
sudah usang juga.Jawaban:
final
specifier untuk mencegah penurunan kelasstd::auto_ptr
pekerjaan tidak lagi diperlukan karena dukungan kelas satu untuk referensi nilai.shrink_to_fit()
fungsi anggota, yang seharusnya menghilangkan kebutuhan pertukaran dengan sementara.= delete
Sintaksnya adalah cara yang jauh lebih langsung untuk mengatakan bahwa fungsi tertentu secara eksplisit ditolak. Ini berlaku untuk mencegah alokasi tumpukan (yaitu,=delete
untuk anggotaoperator new
), mencegah salinan, penugasan, dll.result_of
: Penggunaan templat kelasresult_of
harus diganti dengandecltype
. Saya pikirresult_of
menggunakandecltype
ketika tersedia.NULL
harus didefinisikan ulang sebagainullptr
, tetapi lihat pembicaraan STL untuk mengetahui mengapa mereka memutuskan untuk tidak melakukannya.Saya pikir saya akan berhenti di sana!
sumber
result_of
dari daftar. Meskipuntypename
diperlukan rumit sebelumnya, saya pikirtypename result_of<F(Args...)::type
kadang-kadang bisa lebih mudah dibaca daripadadecltype(std::declval<F>()(std::declval<Args>()...)
, dan dengan penerimaan N3436 ke dalam kertas kerja mereka berdua bekerja untuk SFINAE (yang dulunya merupakan keuntungan daridecltype
yangresult_of
tidak menawarkan)Pada satu titik waktu dikatakan bahwa seseorang harus kembali dengan
const
nilai alih-alih hanya dengan nilai:Ini sebagian besar tidak berbahaya di C ++ 98/03, dan mungkin bahkan menangkap beberapa bug yang terlihat seperti:
Tapi kembali oleh
const
dikontraindikasikan dalam C ++ 11 karena menghambat semantik bergerak:Jadi santai saja dan kode:
sumber
A& operator=(A o)&
bukan mendefinisikanA& operator=(A o)
. Ini mencegah kesalahan konyol dan membuat kelas berperilaku lebih seperti tipe dasar dan tidak mencegah semantik bergerak.Segera setelah Anda dapat meninggalkan
0
danNULL
mendukungnullptr
, lakukanlah!Dalam kode non-generik, penggunaan
0
atauNULL
bukan merupakan masalah besar. Tetapi segera setelah Anda mulai melewati konstanta penunjuk nol dalam kode generik situasinya berubah dengan cepat. Ketika Anda lulus0
ketemplate<class T> func(T)
T
akan dideduksi sebagaiint
dan bukan sebagai pointer nol konstan. Dan itu tidak dapat dikonversi kembali ke konstanta penunjuk nol setelah itu. Ini mengalir ke rawa-rawa masalah yang sama sekali tidak ada jika alam semesta hanya digunakannullptr
.C ++ 11 tidak usang
0
danNULL
sebagai konstanta penunjuk nol. Tetapi Anda harus kode seolah-olah itu.sumber
std::nullptr_t
.0
atauNULL
untuk null pointer").Idioma bool aman →
explicit operator bool()
.Pembuat salinan pribadi (boost :: noncopyable) →
X(const X&) = delete
Mensimulasikan kelas terakhir dengan destruktor pribadi dan warisan virtual →
class X final
sumber
Salah satu hal yang hanya membuat Anda menghindari penulisan algoritma dasar dalam C ++ 11 adalah ketersediaan lambdas dalam kombinasi dengan algoritma yang disediakan oleh perpustakaan standar.
Saya menggunakan itu sekarang dan itu luar biasa seberapa sering Anda hanya mengatakan apa yang ingin Anda lakukan dengan menggunakan count_if (), for_each () atau algoritma lain daripada harus menulis loop sialan lagi.
Setelah Anda menggunakan kompiler C ++ 11 dengan pustaka standar C ++ 11 yang lengkap, Anda tidak punya alasan lagi untuk tidak menggunakan algoritma standar untuk membangun . Lambda baru saja membunuhnya.
Mengapa?
Dalam prakteknya (setelah menggunakan cara penulisan algoritma ini sendiri) rasanya jauh lebih mudah untuk membaca sesuatu yang dibangun dengan kata-kata langsung yang berarti apa yang dilakukan daripada dengan beberapa loop yang harus Anda enkripsi untuk mengetahui artinya. Yang mengatakan, membuat argumen lambda secara otomatis menyimpulkan akan banyak membantu membuat sintaks lebih mudah dibandingkan dengan loop mentah.
Pada dasarnya, algoritma pembacaan yang dibuat dengan algoritma standar jauh lebih mudah karena kata-kata menyembunyikan detail implementasi loop.
Saya menduga hanya algoritma level yang lebih tinggi yang harus dipikirkan sekarang karena kita memiliki algoritma level yang lebih rendah untuk dibangun.
sumber
for_each
dengan lambda lebih baik daripada rentang yang setara untuk loop, dengan isi lambda di loop. Kode ini terlihat kurang lebih sama, tetapi lambda memperkenalkan beberapa tanda baca tambahan. Anda dapat menggunakan hal-hal yang setara sepertiboost::irange
menerapkannya ke lebih banyak loop daripada hanya yang menggunakan iterator. Plus range-range untuk loop memiliki fleksibilitas yang lebih besar, di mana Anda dapat keluar lebih awal jika diperlukan (olehreturn
atau olehbreak
), sedangkan denganfor_each
Anda harus membuang.for
membuatit = c.begin(), const end = c.end(); it != end; ++it
idiom yang biasa mati.for_each
algoritma pada rentang berdasarkan loop adalah bahwa Anda tidak bisabreak
ataureturn
. Yaitu, ketika Anda melihatfor_each
Anda segera tahu tanpa melihat tubuh yang tidak ada trickiness tersebut.std::for_each(v.begin(), v.end(), [](int &i) { ++i; });
denganfor (auto &i : v) { ++i; }
. Saya menerima bahwa fleksibilitas bermata dua (goto
sangat fleksibel, itulah masalahnya). Saya tidak berpikir bahwa kendala tidak mampu menggunakanbreak
dalamfor_each
mengkompensasi versi untuk bertele-tele ekstra itu menuntut - pengguna darifor_each
sini IMO mengorbankan mudah dibaca dan kenyamanan yang sebenarnya untuk jenis gagasan teoritis bahwafor_each
ini pada prinsipnya lebih jelas dan konseptual lebih sederhana. Dalam praktiknya itu tidak jelas atau sederhana.Anda harus menerapkan versi khusus yang
swap
lebih jarang. Dalam C ++ 03, non-throwing yang efisienswap
sering diperlukan untuk menghindari mahal dan membuang salinan, dan karenastd::swap
menggunakan dua salinan,swap
sering kali harus disesuaikan. Dalam C ++,std::swap
penggunaanmove
, dan fokusnya bergeser pada penerapan konstruktor pemindahan yang efisien dan non-lempar dan memindahkan penugasan Karena untuk ini default sering kali baik-baik saja, ini akan jauh lebih sedikit bekerja daripada di C ++ 03.Secara umum sulit untuk memprediksi idiom mana yang akan digunakan karena mereka diciptakan melalui pengalaman. Kita dapat mengharapkan "Efektif C ++ 11" mungkin tahun depan, dan "Standar C ++ 11 Coding" hanya dalam tiga tahun karena pengalaman yang diperlukan belum ada di sana.
sumber
Saya tidak tahu nama untuk itu, tetapi kode C ++ 03 sering menggunakan konstruk berikut sebagai pengganti untuk tugas pindah yang hilang:
Ini menghindari penyalinan karena salin salin digabungkan dengan di
swap
atas.sumber
map
. Teknik yang Anda tampilkan bermanfaat jikamap
sudah ada, bukan hanya sedang dibangun. Contohnya akan lebih baik tanpa komentar "konstruktor default murah" dan dengan "// ..." antara konstruksi dan swapKetika saya perhatikan bahwa kompiler yang menggunakan standar C ++ 11 tidak lagi kesalahan kode berikut:
untuk operator yang seharusnya berisi >>, saya mulai menari. Dalam versi sebelumnya yang harus dilakukan
Lebih buruk lagi, jika Anda harus men-debug ini, Anda tahu betapa mengerikannya pesan kesalahan yang keluar dari ini.
Namun, saya tidak tahu apakah ini "jelas" bagi Anda.
sumber
Pengembalian dengan nilai tidak lagi menjadi masalah. Dengan memindahkan semantik dan / atau optimalisasi nilai kembali (bergantung pada kompiler), fungsi pengkodean lebih alami tanpa overhead atau biaya (sebagian besar waktu).
sumber