7

C++ の参照は、次の C コードを単純化できる便利な構造です。

f(object *p){
  //do something
}

int main(){
  object* p = (object*) calloc(sizeof(object));
  f(p);
}

f(object& o){
  //do something
}

int main(){
  object o = object();
  f(o);
}

共有ポインターは、メモリ管理を簡素化する C++ のもう 1 つの便利な機能です。ただし、参照によって引数を受け入れるshared_ptrような関数に aを渡す方法がわかりませんか?f(object& o)

f(object& o){
  //do something
}

int main(){
  shared_ptr<object> p (new object());
  f(*p);
}

オブジェクトが関数への参照によって渡されると、共有ポインタはインクリメントされますか?

4

4 に答える 4

10

by 値を取る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);
}

無関係な増分と減分 (およびコピーなど) を避けるために、可能な場合はスマート ポインターを参照として渡すことをお勧めします。

于 2009-09-09T22:51:36.043 に答える
2

オブジェクトが関数への参照によって渡されると、共有ポインタはインクリメントされますか?

いいえ、生のポインターにアクセスしてから渡すためです。これに似た何かをしたい:

f(shared_ptr<object> o){
  //do something
}

int main(){
  shared_ptr<object> p (new object());
  f(p);
}
于 2009-09-09T22:47:47.823 に答える
1
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 を渡します。

于 2009-09-09T23:21:41.500 に答える
-1

まず最初に、機能の観点から、C++ の参照はポインターとまったく同じです。それらが言語に追加された唯一の理由は、演算子のオーバーロードの構文をより自然にすることでした。(たとえば、&a+&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 のパラメーターが参照ではなくポインターを受け取った場合とまったく同じことが起こっていることを覚えておいてください。唯一の違いは、& 演算子を明示的に使用しなくても、コンパイラが自動的に変数のアドレスを渡すことです。

私は個人的に変数を参照渡しするのは好きではありません (const 参照渡しは問題ありません)。代わりにポインターを使用することをお勧めします。これにより、呼び出している関数がその引数を変更する可能性があることが呼び出しサイトで明確になるためです (呼び出しサイトでは & 記号が表示されるため)。

平和

于 2009-09-09T23:10:55.827 に答える