【问题标题】:What is wrong with my park_car function?我的 park_car 功能有什么问题?
【发布时间】:2012-05-27 12:50:49
【问题描述】:

我又在为学校做一个任务,我正在慢慢实现它,我不知道为什么我的park_car 函数不起作用,我只是想做一个测试,程序崩溃了......在这里是我的代码。

PS:我无法更改***p2parkboxes,因为它像大多数其他变量一样在起始文件中给出。我只想将第 0 层的第一个元素视为:HH-AB 1234。非常感谢您的帮助。 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;
}

【问题讨论】:

  • 让陌生人通过检查发现代码中的错误是没有效率的。您应该使用调试器或打印语句来识别(或至少隔离)问题,然后返回更具体的问题(一旦您将其缩小到 10 行 test-case)。
  • Parkbox ***p2parkboxes; o_O 虽然您说您不能更改该声明,但无论如何您都应该更改它。最好避免在 C++ 中使用多维、动态分配的数组。更喜欢使用一维数组(或者,如果必须,使用vector&lt;vector&lt;vector&lt;ParkBox&gt;&gt;&gt;)。我敢猜测,与你的导师争辩说三重指针是疯狂的,而不是正确实现这个类会更容易。
  • 最好使用std::string 而不是普通的char*。
  • 供以后参考,请不要在解决后删除您的原始问题(这会使您的问题对未来的访问者无用)。此外,当您想要进行代码审查时,还有一个网站:codereview.stackexchange.com
  • 问题还在,感谢评论链接!

标签: c++ multidimensional-array heap-memory


【解决方案1】:

您没有为 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. 复制发生了(这很明显,因为 this 是用代码编写的东西)并且 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 ,如果发生任何分配,这将导致未定义的行为在你打电话之前

    cout

底线:这行本身没有问题,问题隐藏在 '=' 运算符的实现细节中。

此时,最好将 std::string 用于字符串,而不是使用与隐式 C++ 复制/构造语义混合的锋利、棘手和显式的 C 样式直接内存管理。如果您将 std::vector 用于动态数组,代码也会更好。

【讨论】:

  • 别忘了删除当前的 license_plate!否则你会得到内存泄漏。您还需要仔细检查自我分配,否则您将面临未定义行为的风险。
  • 当然,克里斯。我的代码只“修复”了问题,引入了另一个问题:) 也许使用 C++11 的 move 构造函数在此处使用 license_plate ptr 的直接副本并且没有 strcpy() 调用会更好。
  • 在堆栈上创建一些东西(带有 char* 指针的 Parkbox 实例)(并几乎立即将其删除)。 为什么在堆栈上?它应该在堆上,因为在 Parkbox CTOR 中,我为每个 license_plate 分配内存 ...
  • license_plate 肯定会在堆中。问题是指针(临时堆栈分配的 Parkbox 中的 license_plate)在分配中丢失了。实际上,您在 p2parboxes[0][0][0] 中有一个新的 Parkbox 实例,并且该实例指向已释放的“某物”(在自动生成的复制运算符中使用逐字节复制),因为临时 Parkbox 是已删除。
  • 我已经添加了详细的描述。希望现在一切都清楚了。
【解决方案2】:

这里的问题是你没有深拷贝赋值语义。当您将临时 Parkbox 分配给停车场中的 Parkbox 时,编译器生成的赋值运算符会制作指针 license_plate 的浅表副本,使两个 Parkbox 都指向相同的内存位置。然后临时 Parkbox 超出范围并删除 license_plate。由于另一个 Parkbox 指向同一个位置,因此它的 license_plate 也会被删除。

有几个解决方案。解决该问题的一种方法是定义提供适当语义的赋值运算符和复制构造函数,即执行车牌字符串的深拷贝。更好的选择,也是更好地利用 C++ 的选择,是使用 std::strings 而不是手动分配的 C-strings。我强烈建议使用第二种方法,尽管通过第一种方法可能会很有启发性。

【讨论】:

  • 不幸的是,这个任务不允许使用 std::string :(
【解决方案3】:

来自 OP:

我解决了这个问题:

void Parkbox::change_plate(char *s){
delete [] license_plate;
license_plate = new char[strlen(s)+1];
strcpy(license_plate, s);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-19
    • 2015-05-27
    • 2018-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多