Kembalikan petunjuk cerdas dengan nilai.
Seperti yang Anda katakan, jika Anda mengembalikannya dengan referensi, Anda tidak akan menaikkan jumlah referensi dengan benar, yang membuka risiko menghapus sesuatu pada waktu yang tidak tepat. Itu saja sudah cukup menjadi alasan untuk tidak kembali dengan referensi. Antarmuka harus kuat.
Masalah biaya saat ini diperdebatkan berkat pengoptimalan nilai pengembalian (RVO), jadi Anda tidak akan menimbulkan urutan kenaikan-kenaikan-penurunan atau sesuatu seperti itu di kompiler modern. Jadi cara terbaik untuk mengembalikan a shared_ptr
adalah dengan hanya mengembalikan dengan nilai:
shared_ptr<T> Foo()
{
return shared_ptr<T>(/* acquire something */);
};
Ini adalah peluang RVO yang sangat jelas untuk kompiler C ++ modern. Saya tahu pasti bahwa kompiler Visual C ++ menerapkan RVO bahkan ketika semua pengoptimalan dimatikan. Dan dengan semantik move C ++ 11, kekhawatiran ini menjadi kurang relevan. (Tetapi satu-satunya cara untuk memastikan adalah membuat profil dan bereksperimen.)
Jika Anda masih belum yakin, Dave Abrahams sudah yakin artikel yang membuat argumen untuk dikembalikan berdasarkan nilai. Saya mereproduksi potongan di sini; Saya sangat menyarankan Anda membaca seluruh artikel:
Jujurlah: bagaimana kode berikut memengaruhi perasaan Anda?
std::vector<std::string> get_names();
...
std::vector<std::string> const names = get_names();
Terus terang, meskipun saya harus lebih tahu, itu membuat saya gugup. Pada prinsipnya, ketika get_names()
kembali, kita harus menyalin vector
daristring
s. Kemudian, kita perlu menyalinnya lagi saat kita menginisialisasi
names
, dan kita perlu menghancurkan salinan pertama. Jika ada N string
dalam vektor, setiap salinan dapat memerlukan alokasi memori N + 1 dan sejumlah besar akses data tidak ramah cache> saat konten string disalin.
Alih-alih menghadapi kecemasan semacam itu, saya sering mengabaikan referensi untuk menghindari salinan yang tidak perlu:
get_names(std::vector<std::string>& out_param );
...
std::vector<std::string> names;
get_names( names );
Sayangnya, pendekatan ini jauh dari ideal.
- Kode tumbuh 150%
- Kami harus turun
const
-ness karena kami mengubah nama.
- Seperti yang sering diingatkan oleh programmer fungsional kepada kita, mutasi membuat kode lebih kompleks untuk dipikirkan dengan merusak transparansi referensial dan penalaran persamaan.
- Kami tidak lagi memiliki semantik nilai ketat untuk nama.
Tetapi apakah benar-benar perlu mengacaukan kode kita dengan cara ini untuk mendapatkan efisiensi? Untungnya, jawabannya ternyata tidak (dan terutama tidak jika Anda menggunakan C ++ 0x).