web-dev-qa-db-ja.com

パラメータとしての「newFoo()」と「&Foo()」の違い

特定のコンテキストでのキーワードnewと_&_の違いについていくつか質問があります。

これが私のコードだとしましょう:

_struct Base {};
struct Foo : Base {};
struct Storage
{
    void save(Base * object) {}
    Base * content;
};

int main()
{
    Storage s1, s2;
    s1.save(new Foo());
    s2.save(&Foo());
}
_

Mainの実行後、_s1_はタイプFooのオブジェクトへのポインタを保持します。ただし、_s2_は、タイプBaseのオブジェクトへのポインタを保持します。 _s2.content_は、saveメソッドの実行が完了するまで、タイプFooのオブジェクトのみを指します。

私が間違っている場合は私を訂正してください:

私が理解している限り、new Foo()はタイプFooの新しいオブジェクトへのポインタを作成します。一方、&Foo()は、最初にタイプFooの新しいオブジェクトを作成し、次にそれをポイントします。

では、new Foo()&Foo()の違いは正確には何ですか?明らかに、どちらもタイプFooの既存のオブジェクトへのポインタを提供します。

new Foo()で作成されたオブジェクトが、saveメソッドの実行後も保持されるのに、&Foo()で作成されたオブジェクトが保持されないのはなぜですか?

&Foo()が一時オブジェクトを作成し、保存の実行後に存在しなくなる可能性がありますか?はいの場合、&Foo()を介して作成されたオブジェクトの寿命を延ばして、_s2_が破壊されるまで(少なくとも)ライブにする方法はありますか?

編集1:迅速な回答をありがとうございました!私は単にVisualStudioを使用しているので、おそらく&Foo()コンパイルはMicrosoft固有のものです...

16
Domi P.

では、「new Foo()」と「&Foo()」の違いは正確には何ですか?明らかに、どちらもFoo型の既存のオブジェクトへのポインタを提供します。

new Foo()」で作成されたオブジェクトがsaveメソッドの実行後も保持されるのに、「&Foo()」で作成されたオブジェクトが保持されないのはなぜですか?


new Foo()

_new Foo();
_

これにより、動的に割り当てられたFooオブジェクトが作成され、そのオブジェクトを指すポインタが返されます。動的に割り当てられたオブジェクトは、プログラマーによって明示的に削除されるまで存続します。

_Foo* foo = new Foo();
delete foo; // delete the object.
_

&Foo()

_Foo();
_

これにより、automatic-storageを使用してFooオブジェクトが作成されます。これは、オブジェクトが削除されたときの存続期間が、オブジェクトが存在するスコープによって決定されることを意味します。

_{
  Foo foo{}; // foo lives in automatic storage.
} // end of scope, foo dies
_

あなたの場合、新しいFooオブジェクトを作成し、この匿名オブジェクトのアドレスを_Storage::save_に渡します。このオブジェクトは、完全な式の最後に破棄されます。これは基本的に、s2.save()が戻った後、オブジェクトが破棄され、_s2_でオブジェクトを指すポインターがぶら下がり、逆参照が未定義の動作になることを意味します。


はいの場合、「&Foo()」を介して作成されたオブジェクトの寿命を延ばして、(少なくとも)s2が破壊されるまで存続させるにはどうすればよいですか?

できません。ここでは、_std::unique_ptr_などのスマートポインタが必要になる可能性があります。


一時アドレスの取得は非標準であるため、このコードはそもそも非準拠であることに注意してください。コンパイラはおそらくそれを許可するために拡張機能を使用しています。 MSVCはこれを可能にすることで知られています。

22

Foo()は、新しいtemporaryオブジェクトを作成し、その一時オブジェクトでaddress-of演算子_&_を使用するとそのような一時オブジェクトのアドレスを取得することは許可されていないため、コンパイラエラーが発生します(Foo() is rvalue およびaddress-of演算子はそれらに使用できません)。

_new Foo_を使用して、non一時オブジェクトを作成すると、そのオブジェクトへのポインターが生成されます。このオブジェクトの有効期間は、明示的にdeleteするまでです。そして、それをdeleteしないと、メモリリークが発生します。