shared_ptrとC ++の参照
-
05-07-2019 - |
質問
C ++の参照は、次のCコードを簡素化することができるconveneintコンストラクトです。
f(object *p){
//do something
}
int main(){
object* p = (object*) calloc(sizeof(object));
f(p);
}
to
f(object& o){
//do something
}
int main(){
object o = object();
f(o);
}
共有ポインタは、メモリ管理を簡素化するC ++のもう1つの便利な機能です。ただし、参照によって引数を受け取る f(object& o)
などの関数に shared_ptr
を渡す方法がわかりませんか?
f(object& o){
//do something
}
int main(){
shared_ptr<object> p (new object());
f(*p);
}
共有ポインタは、オブジェクトが関数への参照によって渡されるときにインクリメントされますか?
解決
値で shared_ptr
を取得すると、参照カウントが増加します。これは、 typedef
すると簡単です:
typedef boost:shared_ptr<object> object_ptr;
void foo(object_ptr obj)
{
obj->/* stuff*/;
obj.reset(); //only resets this local copy, that means:
// reduce reference count (back to 1), and
// set obj to point at null.
}
int main(void)
{
object_ptr obj(new object());
foo(obj);
}
参照はエイリアスであることに留意してください。参照渡しする場合、ポインタやコピーなどを渡すのではなく、別のオブジェクトにエイリアスを作成します。 (実際にはポインターとして実装されています):
typedef boost:shared_ptr<object> object_ptr;
void foo(object_ptr& obj)
{
obj.reset(); // the references was never increased, since a copy has not
// been made, this *is* obj in main. so the reference
// goes to 0, and obj is deleted
}
int main(void)
{
object_ptr obj(new object);
foo(obj); // after this, obj has been reset!
}
エラーを防ぐため、常に const
が正しいことを忘れないでください:
typedef boost:shared_ptr<object> object_ptr;
void foo(const object_ptr& obj)
{
obj.reset(); // cannot do!
}
int main(void)
{
object_ptr obj(new object);
foo(obj);
}
余分な増分や減分(およびコピーなど)を避けるために、可能であればスマートポインターを参照として渡すことをお勧めします。
他のヒント
共有ポインタは、オブジェクトが関数への参照によって渡されたときにインクリメントされますか?
いいえ、未加工のポインターにアクセスしてから渡すためです。これに似た何かをしたい:
f(shared_ptr<object> o){
//do something
}
int main(){
shared_ptr<object> p (new object());
f(p);
}
f(object& o){ //do something } int main(){ shared_ptr<object> p (new object()); f(*p); }
共有ポインタがインクリメントされます オブジェクトが参照渡しされたとき 関数へ?
上記のコードでは-いいえ。 p の参照カウンターは常に1になります。これはデバッガで確認できます。 shared_ptrの参照カウンターは、同じオブジェクトを指すshared_ptrインスタンスの数をカウントします。operator*()を呼び出して作成した参照は追跡しません。そして、それは必要ありません- p はスコープの終わりまで機能し、関数呼び出しがこの同じスコープ(またはより深い)にあることが保証されるため、 p は f ()への呼び出し全体の間にあります。だから、すべてがOKです。
... f で o のアドレスを取得し、 f が戻った後に続く場所に保存しない限り。これは必ず避けるべきです-必要な場合はshared_ptrを渡します。
まず最初に、機能の観点から、C ++での参照はポインターとまったく同じです。それらが言語に追加されたのは、演算子のオーバーロードの構文をより自然にするためだけです。 (たとえば、&amp; a +&amp; bの代わりにa + bを書き込むことを許可するには)
CとC ++のコードサンプルはまったく同じではありません。 C ++コードのCバージョンは次のようになります。
f(object *p){
//do something
}
int main(){
object o;
object_constructor(&o);
f(&o);
object_destructor(&o);
}
実際、これはC ++コンパイラが概念的に生成する種類のコードです。
2番目の質問に関して:はい、それは関数fを呼び出す正しい方法です。共有ポインターカウンターは増加しません。 shared_ptrを使用していないかのように、オブジェクトへの実際のポインターが渡されます。ただし、fがファンキーなことをしていない限り、安全です。ちょうどfのパラメーターが参照ではなくポインターを使用した場合とまったく同じことが起こっていることを覚えておいてください。唯一の違いは、コンパイラが明示的に&amp;を使用せずに変数のアドレスを自動的に渡すことです。演算子。
私は個人的に参照渡しで変数を渡すのは好きではありません(const参照で渡すことはできます)。呼び出しサイトで引数を変更する可能性があることを呼び出しサイトで明確にするので、代わりにポインタを使用することを好みます(&amp;記号が呼び出しサイトで表示されるため)。
平和