3

最後に C++ で何かをしたのは何年も前のことです。最近、誰かが C++ の学校のプロジェクトで私に助けを求めてきました。私が見た言語の「機能」に興味をそそられました。

私が覚えているように、クラスのインスタンスをヒープまたはスタックのいずれかに作成できます。

int main() {
  MyClass *inHeap = new MyClass();
  MyClass inStack = MyClass();
}

私が知る限り、最初の変数,は、オブジェクトの実際のインスタンスを指すポインター (4 バイト? 8 バイト? そのようなもの) を保持するのに十分な量inHeapのスタックをコンパイラーにスタック フレームに予約させます。mainヒープに住んでいます。

また、2 番目の変数は、スタック フレーム内にinStackの完全なインスタンスを保持するのに十分な量のスタックをコンパイラに予約させます。MyClassmain

では、私の質問に移ります。のインスタンスを返す関数があるとしますMyClass。最初は、ヒープ内のインスタンスしか返せないと思っていました。

MyClass *createInHeap() {
  return new MyClass();
}
int main() {
  MyClass* inHeap = createInHeap();
}

しかし、私が見たのは次のとおりです。

MyClass createInStack() {
  MyClass c = MyClass();
  return c;
}
int main() {
  MyClass inStack = createInStack();
}

ここで何が起こっているのですか?

  • のインスタンスのメモリはMyClassのスタック フレームに予約されていますcreateInStackか? この場合、このコードは、関数が戻るときにインスタンスをスタック フレームに強制的にコピーしますか? このコピーはどのように実行されますか、つまり、関数内でコピー コンストラクターが自動的に呼び出されるだけですか?maincreateInStackmain

  • 私が考えたもう 1 つの可能性は、コンパイラが十分にスマートで、スタック フレームMyClass内のインスタンス用のメモリを既に予約しているということです。mainこれは存在しますか?これは、おそらく高価なコピーを作成することを避けるためのある種の最適化ですか?

最後の質問として、スタックにインスタンスを作成した場合、そのデストラクタは正確にいつ呼び出されますか? それが作成されたスコープが終了するのはいつですか?

4

2 に答える 2

9

このようなことをしている場合:

MyClass createInStack() 
{
  MyClass return_value;
  return return_value;
}

int main() 
{
  MyClass inStack = createInStack();
}

次に、はい、cのスタックで論理的に作成され、createInStack()そのコピーが論理的に返され、 にコピーさinStackmainます。

このすべての論理コピーのために、値による戻りは非効率的であるという一般的な誤解があります。ただし、名前付きの戻り値の最適化により、これは実際に実際に起こることではありません。呼び出し関数の構築ステップは、呼び出された関数に延期されます。次のようなものになります(疑似コード):

void createInStack(MyClass &return_value)
{
  return_value.MyClass(); // construct return_value (not actually valid syntax)
}

int main()
{
  MyClass inStack; // except don't call the constructor
  createInStack(inStack);
}

ご覧のとおり、実際のコピーは行われません。

さらに、コンパイラは他の最適化を行う場合があります。決して使用されず、作成しないと判断することさえありinStackますが、少なくとも名前付きの戻り値の最適化により、多くのコピーが回避されることは間違いありません。

于 2013-04-28T17:41:03.667 に答える
1

newまた、呼び出しはコストのかからない操作ではないことも指摘しておく必要があります。かなりのオーバーヘッドが発生する可能性があり、スタック上にローカル コピーを作成するよりも確実に多くのメモリを使用します。もちろん、deleteプログラマが処理して記憶する必要があり、ゼロ以上の時間もかかります。

したがって、いつものように、より良い設計上の決定であり、何が起こっているのかを理解しています (また、以前の回答で既に説明されている「戻り値の最適化」を理解しています)。非常に大きなクラスはコピーに時間がかかりますが、少数の値しかない小さなクラスは、割り当てて解放するよりもスタックにコピーする方が速い場合があります。

于 2013-04-28T18:21:57.713 に答える