5

絶対初級第2版のC++プログラミング本に次のような記述がありました。

HeapPoint::HeapPoint(int x, int y): thePoint(new Point(x,y)) { }

これは次と同じですか:

HeapPoint::HeapPoint(int x, int y) { thePoint = new Point(x,y); }

そして、コンストラクターでこれを行っているため、xと に割り当てられる値は何yですか? instedxyin に値を書き込む必要がありnew Point(x,y)ますか? それとも、そのように正しいですか?

更新:本のように、関数に次のように初期x化するというアイデアを得たと思います:y

HeapPoint myHeapPoint(2,4);
4

6 に答える 6

4

一般に、最初の構造、つまり初期化子リストを使用することを優先する必要があります。

次の場合は、2 番目の構文が適しています。

  1. あなたはtry..catchを入れたいか、
  2. これらをいくつか持っていて、それらを通常のポインターとして保存しようとしています。すべての割り当てが成功したことがわかるまで、ある種の auto_ptr / unique_ptr を使用してこれを処理し、その後それらを解放します。これは、おそらくデストラクタでそれらを削除するためですが、コンストラクタがスローした場合、デストラクタは呼び出されません。
于 2011-02-14T10:02:51.473 に答える
2

が生のポインターであると仮定するthePointと、すべての意図と目的で同じです。最初のバージョンは を初期化しますthePointが、2 番目のバージョンはそれに代入しますが、まったく同じマシン コードを生成するという点でさえ、効果はほとんど常に同じです。

それらが同じではないのはいつですか?

  1. thePointある種のスマート ポインターの場合、最初の形式は新しい Point をそのコンストラクターに渡すことによって初期化しますが、2 番目の形式はおそらくそれをゼロで初期化し、新しい Point を代入演算子に渡します。
  2. がいくつかのメンバー変数の 1 つである場合thePoint、最初の形式はクラス定義に現れる順序で初期化しますが、2 番目の形式はコンストラクターの本体に代入します。したがって、物事が「水和」される順序は、2 つの形式の間で異なる場合があり、一部のメンバー変数が他の変数に依存している場合に問題になる可能性があります。

あなたが初心者の場合、これらのほとんどはおそらく意味のないものです。しかし、それについて心配する必要はありません。これらの違いは非常に微妙であり、ほとんど問題になりません。(他にも例外はあると思いますが、今は思い浮かびません。)

最終的にはスタイルと一貫性の問題であり、代入形式よりも初期化形式を好みます。

于 2011-02-14T09:48:50.793 に答える
1

2 つの形式は、初期化リストが変数に直接配置される値を与えるという点でまったく同じではありませんが、それ以外の場合、変数は適切な場合はデフォルトで初期化されます (たとえば、std::strings はデフォルトで空ですが、int、doubleメンバー変数は実質的にランダムな値を持ちます)、代入操作が発生すると上書きされます。この上書きは効率が低下する可能性がありますが、作成後に変更が許可されていない一部の定数および参照メンバー変数では無効になる可能性もあります。一般に、可能な限り初期化子リストを使用してください。そうすれば、大きな間違いはありません。最初に他の手順を実行する必要があるため、何かをまだ初期化できないことがわかった場合にのみ、明示的な代入ステートメントをコンストラクタ本体内に配置する必要があります。

于 2011-02-14T10:04:58.870 に答える
0

最初のものは2番目のものと同じではありません。

この特定のケースでは、おそらく同じ結果が得られます。ただし、Point簡単に代入演算子を実装し、new Point「異なる」何かを実行できます(私は本を持っていないので、すべての詳細を知りません)。同様に、代入演算子は期待どおりのことを行う必要があります...ただし、thePointは、 vsを使用した場合に(何らかの奇妙な理由で)異なる動作をする可能性のあるコンテナー(スマートポインターなど)である可能性があります。initialization(Point)default initialization followed by assignment

この場合、これらの詳細は重要ではない可能性がありますが、初期化の順序と実行に影響します。プログラムが成長するとき、違いは重要になります。そのとき、初期化には時間がかかります。オブジェクトが正しく初期化されていること、つまり、オブジェクトが適切に(最初に)構築され、正しい順序で構築されていることを確認する必要があります。最も明白なケース:デフォルトのコンストラクターがパラメーターを持つコンストラクターとは異なる動作をする場合、特にコンストラクターが割り当てを生成する場合、またはその他の時間のかかる(または動作が異なる)副作用がある場合に違いが生じます。

そして、これをコンストラクターで行っているので、intxとintyに割り当てられた値は何ですか?

それは完全にPointのコンストラクタに依存します。

xとyの値を新しいPoint(x、y)に書き込む必要がありますか?または、それはそのように正しいですか?

(ほとんどのチームにとって)推奨される方法は、可能な限り初期化リストと正式なコンストラクターを使用し、正しい初期化をサポートするように型を作成することです。コードベースが大きくなると、微妙なことがたくさん出てきます。このコンストラクターは初期化リストを使用します。

HeapPoint::HeapPoint(int x, int y): thePoint(new Point(x,y)) { }

次のようにthePointを宣言する場合は、仮想的なケースで適切な初期化が必要になる可能性があります。

const Point* const thePoint;

1つ目constは、ポイントを変更できないことを意味します(たとえば、Point.xまたはPoint.y)。2番目の定数は、変数に新しい割り当てを割り当てることができないことを意味します。OPの例の簡単な例ですが、プログラムが成長するにつれて間違いなく役立ちます。

于 2011-02-14T10:00:17.140 に答える
0

どちらも同じです。最初のケース:

HeapPoint::HeapPoint(int x, int y): thePoint(new Point(x,y)) { }

thePointが属するクラスのコンストラクタを使用し、 に新しく割り当てられたメモリを指すようにしPointます。

2 番目のケースでもメモリが割り当てられ、そのアドレスが割り当てられます。thePoint

于 2011-02-14T10:03:52.837 に答える
0

最初のケースでは、メンバーをセットアップするために初期化リストthePointを使用しますが、2番目の例ではコンストラクターの本体を使用します。オブジェクトが構築される前に初期化リストが使用され、これが完了するとコンストラクタ本体が使用されるため、背後で行われる作業は同じではありません。

そう:

  • あなたの最初のケースでは、あなたのメンバーthePointは直接構築されていますthePoint(new Point(x,y))

  • 2番目のケースでは、おそらくデフォルトのコンストラクターが利用可能であるため、最初に割り当てられます。次に、構築されたオブジェクトは、本体で行われた呼び出しでオーバーライドされます(はい、同じものですが、同じ場所ではありません)!! したがって、ここで効率が失われます。

初期化リストが存在する場合、これには正当な理由があります (C++ は非常に正確な言語であり、構文は非常に厳密ですが、C から来る醜いものはすべて論理的です)。たとえば、クラスが参照メンバーを使用した場合、オブジェクトが完全に構築されないため、初期化リストを使用する必要があります。

class A
{
public:
    B& _b;
    C& _c;

    A(B& b, C& c):_b(b), _c(c) // compiles !
    {

    }

    A(B& b, C& c)
    {
        _b(b); // does not compile !
        _c(c); // does not compile !
    }
}

ここで、最初のコンストラクターで行った場合(逆順_c(c), _b(b))、クラスのコンストラクターをコピーBC、とにかく同じ順序で呼び出されることに注意してくださいあなたがそれらを書くように注文してください!!!!_b_c

于 2011-02-14T10:18:39.897 に答える