1

私は再び学校でタスクを実行していますが、ゆっくりと実装しています。park_car関数が機能しない理由がわかりません。テストを実行したかっただけで、プログラムがクラッシュします...これが私のコードです。

PS:***p2parkboxes他のほとんどの変数と同じようにスターターファイルで指定されているため、変更できません。フロア0の最初の要素をHH-AB1234として表示したいだけです。ご協力いただければ幸いです。PS2:std :: stringも使用できません。また、タスクでは許可されていません。

#include <iostream>
#include <cstring>
using namespace std;

#define EMPTY "----------"
class Parkbox{
    char *license_plate; // car's license plate
    public:
    Parkbox(char *s = EMPTY); // CTOR
    ~Parkbox(); // DTOR
    char *get_plate(){return license_plate;}
};
class ParkingGarage{
    Parkbox ***p2parkboxes;
    //int dimensions_of_parkhouse[3]; // better with rows,columns,floors
    int rows,columns,floors; // dimensions of park house
    int total_num_of_cars_currently_parked;
    int next_free_parking_position[3];
    // PRIVATE MEMBER FUNCTION
    void find_next_free_parking_position();
    public:
    ParkingGarage(int row, int col, int flr);// CTOR,[rows][columns][floors]
    ~ParkingGarage(); // DTOR
    bool park_car(char*); // park car with license plate
    bool fetch_car(char*); // fetch car with license plate
    void show(); // show content of garage floor
    // by floor
};

Parkbox::Parkbox(char *s ) { // CTOR
    license_plate = new char[strlen(s)+1];
    strcpy(license_plate, s);
    //cout << "ParkBox CTOR" << endl;
}
Parkbox::~Parkbox() { // DTOR
    delete [] license_plate;
    //cout << "ParkBox DTOR" << endl;
}

ParkingGarage::ParkingGarage(int row, int col, int flr){
    rows = row; columns = col; floors = flr;
    p2parkboxes = new Parkbox**[row];
    for (int i = 0; i < row; ++i) {
        p2parkboxes[i] = new Parkbox*[col];

        for (int j = 0; j < col; ++j)
            p2parkboxes[i][j] = new Parkbox[flr];
    }

}

ParkingGarage::~ParkingGarage(){

    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < columns; ++j)
            delete [] p2parkboxes[i][j];

        delete [] p2parkboxes[i];
    }
    delete [] p2parkboxes;
}

void ParkingGarage::show(){
    int i,j,k;
    for (i = 0 ; i < floors; i++){
        cout << "Floor" << i << endl;
        for (j=0;j<rows;j++){
            for (k=0;k<columns;k++){
                cout << p2parkboxes[j][k][i].get_plate() << "  ";
            }
            cout << endl;
        }
    }
}

bool ParkingGarage::park_car(char*s){

    p2parkboxes[0][0][0] = Parkbox(s); //test
    //p2parkboxes[0][0][0] = s; //test

    return true;
}


int main(void) {
    // a parking garage with 2 rows, 3 columns and 4 floors
    ParkingGarage pg1(2, 3, 4);
    pg1.park_car("HH-AB 1234");
    /*pg1.park_car("HH-CD 5678");
      pg1.park_car("HH-EF 1010");
      pg1.park_car("HH-GH 1235");
      pg1.park_car("HH-IJ 5676");
      pg1.park_car("HH-LM 1017");
      pg1.park_car("HH-MN 1111"); */
    pg1.show();
    /*pg1.fetch_car("HH-CD 5678");
      pg1.show();
      pg1.fetch_car("HH-IJ 5676");
      pg1.show();
      pg1.park_car("HH-SK 1087");
      pg1.show();
      pg1.park_car("SE-AB 1000");
      pg1.show();
      pg1.park_car("PI-XY 9999");
      pg1.show(); */
    return 0;
}
4

3 に答える 3

6

Parkboxクラスのコピーコンストラクターを宣言していません。だから、ライン

p2parboxes[0][0][0] = Parkbox(s)

スタック上に何か(char *ポインターを持つParkboxのインスタンス)を作成します(そしてそれをほぼ即座に削除します)。これを修正するには、次のように定義します。

Parkbox& operator = Parkbox(const Parkbox& other)
{
    license_plate = new char[strlen(other.get_plate())+1];
    strcpy(license_plate, other.get_plate());
    return *this;
}

のワークフローを見てみましょう

p2parboxes[0][0][0] = Parkbox(s)

ライン。

  1. 最初に、コンストラクターが呼び出され、Parkboxのインスタンスがスタック上に作成されます(これをtmp_Parkboxと呼びます)。
  2. このコンストラクター内でlicense_plateが割り当てられ、0xDEADBEEFの場所を指しているとしましょう。
  3. コピーが行われ(これはコードで記述されているため明らかです)、p2parboxes [0][0][0]にtmp_Parkboxの正確なコピーが含まれるようになりました。
  4. これで、tmp_Parkboxのスコープが終了し、tmp_Parkboxのデストラクタが呼び出され、tmp_Parkbox.license_plate(0xDEADBEEF ptr)の割り当てが解除されます。
  5. p2parboxes [0] [0] [0]にはまだParkboxの「有効な」インスタンスが含まれており、p2parboxes [0] [0] [0] .license_plateはまだ0xDEADBEEFであり、呼び出す前に割り当てが発生した場合、未定義の動作につながりますthe

    cout << p2parboxes [0] [0] [0] .license_plate;

結論:行自体に問題はありません。問題は「=」演算子の実装の詳細に隠されています。

この時点では、文字列にstd :: stringを使用する方が非常に優れており、暗黙のC++コピー/構築セマンティクスと混合された非常に鋭くトリッキーで明示的なCスタイルの直接メモリ管理ではありません。動的配列にstd::vectorを使用すると、コードも改善されます。

于 2012-05-20T23:53:31.523 に答える
2

ここでの問題は、深いコピー割り当てのセマンティクスがないことです。一時的なParkboxを駐車場のParkboxに割り当てると、コンパイラによって生成された割り当て演算子は、ポインタlicense_plateの浅いコピーを作成し、両方のParkboxが同じメモリ位置を指すようにします。次に、一時的なParkboxはスコープ外になり、license_plateを削除します。他のParkboxが同じ場所を指しているため、そのlicense_plateも削除されます。

いくつかの解決策があります。この問題を解決する1つの方法は、適切なセマンティクスを提供する、つまりナンバープレート文字列のディープコピーを実行する代入演算子とコピーコンストラクターを定義することです。より良いオプション、およびC ++をより有効に活用するオプションは、手動で割り当てられたC文字列の代わりにstd::stringsを使用することです。最初のアプローチを実行することは有益かもしれませんが、私は2番目のアプローチを強くお勧めします。

于 2012-05-21T00:21:44.707 に答える
0

OPから:

私は問題を解決しました:

void Parkbox::change_plate(char *s){
delete [] license_plate;
license_plate = new char[strlen(s)+1];
strcpy(license_plate, s);
}
于 2012-12-07T12:49:17.693 に答える