0

ここで何が壊れているのかを理解しようとしている初心者/学生プログラマー。

「レッグ」クラスと「ルート」クラスがあり、以前のルート オブジェクトをレッグ オブジェクトに追加することでルートが構築されます。

ルート クラスには 2 つのコンストラクターがあります。1 つは 1 つの区間を使用して最初のルートを作成するためのもので、もう 1 つは前のルートと別の区間を使用して後続のルートを構築するためのものです。

すべてがうまくいくようです

  • 脚のみのコンストラクターで最初のルートを作成する

  • leg+route コンストラクターを使用して 2 番目のルートを作成する

  • leg+route コンストラクターで 3 番目のルートを作成する

ただし、2 番目と 3 番目を作成したのと同じ方法で 4 番目のルートを作成しようとすると、プログラムはコンパイルされますが、プログラムが最初のルート オブジェクトに到達するとクラッシュします。

次のようにコードします。

/////////////////////////////
/* includes and namespaces */
/////////////////////////////


#include <iostream>
using std::cin;
using std::cout;
using std::endl;

#include <ostream>
using std::ostream;


#include <cstdlib> // use for: atof(), atoi()




///////////////////////
/* const definitions */
///////////////////////




////////////////////////
/* struct definitions */
////////////////////////


///////////////////////
/* class definitions */
///////////////////////

class Route;

class Leg
{
  private:
    const char* const startCity;
    const char* const endCity;
    const int length;


  public: 
    Leg( const char* const, const char* const, const int );
    friend void printLeg( ostream&, const Leg&);


    friend void printRoute( ostream&, const Route& );

};

class Route
{
  private:
    const Leg** legsPtrArray;
    const int totalLegs;


  public:
    Route( const Leg& );
    Route( const Route&, const Leg& );
    Route( const Route&);  
    ~Route();

    friend void printRoute( ostream&, const Route& );



};


/////////////////////////
/* function prototypes */
/////////////////////////




///////////////////
/* main function */
///////////////////

int main()
{


  Leg Leg1( "San Francisco", "Reno", 218 );

  Leg Leg2( "Reno", "Salt Lake City", 518 );

  Leg Leg3( "Salt Lake City", "Kansas City", 604 );

  Leg Leg4( "Kansas City", "Indianapolis", 482 );

  Leg Leg5( "indianapolis", "NYC", 709 );

  cout << "Legs loaded, press [enter] to print each leg" << endl;

  cin.get();

  cout << "Leg 1: " << endl << endl;
  printLeg( cout, Leg1 );
  cin.get();

  cout << "Leg 2: " << endl << endl;
  printLeg( cout, Leg2 );
  cin.get();

  cout << "Leg 3: " << endl << endl;
  printLeg( cout, Leg3 );
  cin.get();  

  cout << "Leg 4: " << endl << endl;
  printLeg( cout, Leg4 );
  cin.get();  

  cout << "Leg 5: " << endl << endl;
  printLeg( cout, Leg5 );
  cin.get();

  cout << "Building complete route: " << endl << endl;

  Route Route1( Leg1 );

  Route Route2( Route1, Leg2 );

  Route Route3( Route2, Leg3 );

  cout << "Route built! Press [enter] to print" << endl << endl;

  cin.get();

  printRoute( cout, Route3);

  /*

  Route Route4( Route3, Leg4 );

  cout << "Route built! Press [enter] to print" << endl << endl;

  cin.get();

  printRoute( cout, Route4);

  */

  /*

  Route Route5( Route4, Leg5 );

  cout << "Route built! Press [enter] to print" << endl << endl;

  cin.get();

  printRoute( cout, Route5);

  */

  cout << endl;

  cout << "Press [enter] to quit " << endl;

  cin.get();


}

//////////////////////////
/* function definitions */
//////////////////////////


Leg::Leg( const char* const startCityToLoad, const char* const endCityToLoad, const int lengthToLoad )
 : startCity( startCityToLoad ), endCity( endCityToLoad ), length( lengthToLoad )
{

}

void printLeg( ostream& out, const Leg& legToPrint )
{
  out << "Leg start city: " << legToPrint.startCity << endl;
  out << "Leg end city: " << legToPrint.endCity << endl;
  out << "Leg length: " << legToPrint.length << " miles" << endl;

}

Route::Route( const Leg& legToAdd)
: totalLegs( 1 ), legsPtrArray ( new const Leg*[totalLegs] )
{

  legsPtrArray[0] = &legToAdd;

}

Route::Route( const Route& subRoute, const Leg& legToAdd)
: totalLegs( subRoute.totalLegs + 1 ), legsPtrArray ( new const Leg*[totalLegs] )
{

  for (int i = 0; i < subRoute.totalLegs ; i++)
  {
    legsPtrArray[i] = subRoute.legsPtrArray[i];

  }

  legsPtrArray[subRoute.totalLegs] = &legToAdd;

}

Route::Route( const Route& routeCopy )
: totalLegs( routeCopy.totalLegs ), legsPtrArray ( routeCopy.legsPtrArray )
{

}

Route::~Route()
{
  delete[] legsPtrArray;
}

void printRoute( ostream& out, const Route& routeToPrint )
{

  out << "Route: from " 
    << routeToPrint.legsPtrArray[0]->startCity 
    << " to "
    << routeToPrint.legsPtrArray[0]->endCity 
  ; 

  for (int i = 1; i < routeToPrint.totalLegs; i++)
  {
    out 
      << " to " 
      << routeToPrint.legsPtrArray[i]->endCity;
  }

  out << endl << endl;



  int routeLength = 0;

  for (int i = 0; i < routeToPrint.totalLegs; i++)
  {
    routeLength = 
      routeLength + routeToPrint.legsPtrArray[i]->length;

  }

    out << "Route Length: " << routeLength << " miles" << endl;

}

そのままで、これは正常にコンパイルおよび実行されます。

周りのコメントを削除すると

  /*

  Route Route4( Route3, Leg4 );

  cout << "Route built! Press [enter] to print" << endl << endl;

  cin.get();

  printRoute( cout, Route4);

  */

プログラムは脚を正常に作成し、最初のルートに到達するとクラッシュします。

私はやっているに違いないことを知っています....ポインターに何か問題がありますが、何が、なぜそれがこの特定の方法でプログラムをクラッシュさせるのかわかりません。

誰かが私よりも洞察力があれば、助けていただければ幸いです。

4

1 に答える 1

0

あなたの問題は、イニシャライザリストの要素が構築される順序です。

Route クラスでメンバー宣言を交換してみてください。次のようになります。

class Route
{
  private:
  const int totalLegs; // totalLegs comes first
  const Leg** legsPtrArray; // array comes next

私のシステムで動作することを確認しました。

理由を理解するには、こちらをご覧ください。

編集:私が得た出力を追加します:

Leg 5:

Leg start city: indianapolis
Leg end city: NYC
Leg length: 709 miles

Building complete route:

Route built! Press [enter] to print


Route: from San Francisco to Reno to Salt Lake City to Kansas City

Route Length: 1340 miles
Route built! Press [enter] to print


Route: from San Francisco to Reno to Salt Lake City to Kansas City to Indianapolis

Route Length: 1822 miles

Press [enter] to quit

編集:この癖を説明しています...

どの C++ クラスもデストラクタを 1 つだけ持つことができますが、コンストラクタは複数持つことができます。

ここで、デストラクタの要件の 1 つは、オブジェクト (プリミティブまたはそれ以外) のフィールドを、それらの構築とは逆の順序で破棄する必要があるということです。

これは、明確に定義された構築順序が 1 つだけ存在する必要があることを意味します。つまり、フィールドの構築順序は、コンストラクターの初期化リストで指定された順序に依存することはできません。クラスは複数のコンストラクターを持つことができ、それぞれが初期化リスト内のフィールドの独自の順序を指定するためです。したがって、コンパイラは、初期化リストの順序ではなく、クラス定義のフィールドの順序を初期化順序として使用します。

プログラムでは、基本的に、配列legsPtrArrayはその長さの前に初期化totalLegsされていました (プログラムで指定された順序のため)。の未定義の値はtotalLegsジャンクになり、配列の初期化が失敗します。

于 2013-09-30T05:18:31.720 に答える