Apa metode terbaik untuk meneruskan sebuah shared_ptr
dari tipe turunan ke fungsi yang mengambil shared_ptr
tipe dasar?
Saya biasanya melewatkan shared_ptr
referensi untuk menghindari salinan yang tidak perlu:
int foo(const shared_ptr<bar>& ptr);
tetapi ini tidak berhasil jika saya mencoba melakukan sesuatu seperti
int foo(const shared_ptr<Base>& ptr);
...
shared_ptr<Derived> bar = make_shared<Derived>();
foo(bar);
Saya bisa menggunakan
foo(dynamic_pointer_cast<Base, Derived>(bar));
tetapi ini tampaknya kurang optimal karena dua alasan:
- A
dynamic_cast
tampaknya agak berlebihan untuk pemeran turunan-ke-dasar sederhana. - Seperti yang saya pahami,
dynamic_pointer_cast
membuat salinan (meskipun sementara) dari pointer untuk diteruskan ke fungsi.
Apakah ada solusi yang lebih baik?
Pembaruan untuk anak cucu:
Ternyata itu adalah masalah file header yang hilang. Juga, apa yang saya coba lakukan di sini dianggap sebagai antipattern. Umumnya,
Fungsi yang tidak mempengaruhi masa pakai objek (yaitu, objek tetap valid selama durasi fungsi) harus menggunakan referensi atau penunjuk biasa, misalnya
int foo(bar& b)
.Fungsi yang mengkonsumsi suatu objek (yaitu pengguna akhir dari objek tertentu) harus mengambil
unique_ptr
nilai, misalnyaint foo(unique_ptr<bar> b)
. Penelepon harusstd::move
memasukkan nilai ke dalam fungsi.Fungsi yang memperpanjang umur suatu objek harus
shared_ptr
berdasarkan nilai, misalnyaint foo(shared_ptr<bar> b)
. Nasihat biasa untuk menghindari referensi melingkar berlaku.
Lihat pembicaraan Kembali ke Dasar Herb Sutter untuk detailnya.
sumber
shared_ptr
? Mengapa tidak ada referensi konstanta bar?dynamic
pemain hanya diperlukan untuk downcasting. Juga, meneruskan pointer yang diturunkan seharusnya bekerja dengan baik. Ini akan membuat barushared_ptr
dengan refcount yang sama (dan meningkatkannya) dan penunjuk ke basis, yang kemudian mengikat ke referensi const. Karena Anda sudah mengambil referensi, saya tidak mengerti mengapa Anda ingin mengambilnyashared_ptr
sama sekali. TerimaBase const&
dan teleponfoo(*bar)
.foo(bar)
) tidak berfungsi, setidaknya di MSVC 2010.shared_ptr
untuk diteruskan ke fungsi? Saya cukup yakin tidak ada cara untuk menghindarinya.Jawaban:
Meskipun
Base
danDerived
yang kovarian dan pointer baku untuk mereka akan bertindak sesuai,shared_ptr<Base>
danshared_ptr<Derived>
yang tidak kovarian. Inidynamic_pointer_cast
adalah cara yang benar dan paling sederhana untuk menangani masalah ini.( Edit:
static_pointer_cast
akan lebih sesuai karena Anda melakukan transmisi dari turunan ke basis, yang aman dan tidak memerlukan pemeriksaan waktu proses. Lihat komentar di bawah.)Namun, jika
foo()
fungsi Anda tidak ingin mengambil bagian dalam memperpanjang masa pakai (atau, lebih tepatnya, mengambil bagian dalam kepemilikan bersama objek), sebaiknya terimaconst Base&
dan dereferensishared_ptr
saat meneruskannyafoo()
.void foo(const Base& base); [...] shared_ptr<Derived> spDerived = getDerived(); foo(*spDerived);
Selain itu, karena
shared_ptr
tipe tidak bisa menjadi kovarian, aturan konversi implisit di seluruh tipe kembalian kovarian tidak berlaku saat mengembalikan tipeshared_ptr<T>
.sumber
shared_ptr<Derived>
secara implisit dapat dikonversishared_ptr<Base>
, jadi kode harus bekerja tanpa kesalahan casting.shared_ptr<Ty>
memiliki konstruktor yang mengambil ashared_ptr<Other>
dan melakukan konversi yang sesuai jikaTy*
secara implisit dapat dikonversiOther*
. Dan jika pemeran diperlukan,static_pointer_cast
apakah yang sesuai di sini, bukandynamic_pointer_cast
.shared_ptr
untuk menghindari jumlah referensi, maka sebenarnya tidak ada alasan bagus untuk menggunakan ashared_ptr
di tempat pertama. Sebaiknya gunakanconst Base&
sebagai gantinya.static_pointer_cast
, terima kasih.Ini juga akan terjadi jika Anda lupa menentukan warisan publik pada kelas turunan, yaitu jika seperti saya Anda menulis ini:
class Derived : Base { };
sumber
class
adalah untuk parameter template;struct
adalah untuk menentukan kelas. (Ini paling banyak 45% lelucon.)Sepertinya Anda berusaha terlalu keras.
shared_ptr
murah untuk disalin; itulah salah satu tujuannya. Mengedarkannya dengan referensi tidak akan menghasilkan banyak hal. Jika Anda tidak ingin berbagi, teruskan penunjuk mentah.Meskipun demikian, ada dua cara untuk melakukan ini yang dapat saya pikirkan:
foo(shared_ptr<Base>(bar)); foo(static_pointer_cast<Base>(bar));
sumber
shared_ptr
implementasi yang dikirimkan Microsoft.Periksa juga apakah
#include
file header yang berisi deklarasi lengkap kelas turunan ada di file sumber Anda.Saya punya masalah ini. Itu
std::shared<derived>
tidak akan dilemparkan kestd::shared<base>
. Saya telah mendeklarasikan kedua kelas ke depan sehingga saya dapat menyimpan petunjuk kepada mereka, tetapi karena saya tidak memiliki#include
kompilator tidak dapat melihat bahwa satu kelas diturunkan dari yang lain.sumber