C ++块类型是有效错误

时间:2015-05-02 05:10:06

标签: c++

我的代码:

class item{
int plu;
char * name;
double price;
double inv;
public:
void setPLU(int g) { plu = g; }
void setName(const char * p) { name = copyStr(p); }
void setPrice(double g) { price = g; }
void setInventory(double g) { inv = g; }
int getPlu() { return plu; }
char*getName() { return name; }
double getPrice() { return price; }
double getInventory() { return inv; }
item(){
    name = nullptr;
}
~item(){
    delete name;
}
};
class puItem : public item{
bool type;
public:
void setType(bool g) { type = g; }
bool getType() { return type; }
};
class nodeU{
puItem fruit;
nodeU * next;
public:
nodeU * getNext(){ return next; }
puItem getFruit(){ return fruit; }
void setNext(nodeU * g){ next = g; }
void setFruit(puItem g) { fruit = g; }
nodeU(){
    next = nullptr;
}
};
class linkedListU{
nodeU * head;
int size;
public:
nodeU * getHead(){
    return head;
}

void setHead(nodeU * n){
    head = n;
}
//Append
void appendNode(nodeU * n){
    if (head == nullptr){
        head = n;
    }
    else{
        nodeU * iter = head;
        while (iter){
            iter = iter->getNext();
        }
        iter->setNext(n);
    }
    size++;
}
linkedListU()
{
    head = nullptr;
    size = 0;
}
puItem * pluLookup(int g){
    nodeU * iter = head;
    while (iter)
    {
        if ((iter->getFruit()).getPlu() == g)
            return &(iter->getFruit());
        iter = iter->getNext();
    }
    return nullptr;
}

};
void checkout(linkedListP, linkedListU);
linkedListU unitList;
linkedListP poundList;
nodeU * inputU=new nodeU;
int main()
{
    ifstream infile;
    ofstream outfile;
    int tempPlu;
    string tempName;
    bool tempType;
    double tempPrice, tempInv;
    infile.open("products.txt");
        puItem unit;

        infile >> tempPlu;
        if (!infile.good())
        {
            infile.clear();
            infile.ignore();
        }
        infile >> tempName;
        if (!infile.good())
        {
            infile.clear();
            infile.ignore();
        }
        infile >> tempType;
        if (!infile.good())
        {
            infile.clear();
            infile.ignore();
        }
        infile >> tempPrice;
        if (!infile.good())
        {
            infile.clear();
            infile.ignore();
        }
        infile >> tempInv;
        if (!infile.good())
        {
            infile.clear();
            infile.ignore();
        }
        if (tempType == 0){
            unit.setInventory(tempInv);
            unit.setName(tempName.c_str());
            unit.setPLU(tempPlu);
            unit.setType(tempType);
            unit.setPrice(tempPrice);
            inputU->setFruit(unit);
            unitList.appendNode(inputU);    
        }


    checkout(poundList, unitList);
    system("pause");
    return 0;
}
void checkout(linkedListU p){

int key = -10;
puItem * searchU=nullptr;
int counter = 0;
double total = 0;
double amount;
cout << "Enter the plu for the item you want or enter 0 to exit: ";
cin >> key;
while (key < 0)
{
    cout << "\nInvalid input please re enter: ";
    cin >> k
    searchU = p.pluLookup(key);
}
while (key)
{

当它进入plu查找它会抛出错误,我似乎无法找出原因。 我知道错误是删除了两次但我在这段代码中找不到任何实例。

1 个答案:

答案 0 :(得分:1)

您的代码存在很多问题,其中大部分都是由于您的类无法安全复制(它们缺少用户定义的复制构造函数和赋值运算符以及析构函数)。请参阅3的规则:

What is The Rule of Three?

您的checkout函数具有以下原型:

void checkout(linkedListU p){

这意味着您按值传递linkedListU。由于linkedListU未能遵循3的规则,因此当您按值传递此类型时,将调用编译器定义的复制构造函数,该构造函数仅生成浅拷贝,从而导致未定义的行为。

您的链接列表的成员是指向动态分配内存的指针,需要按照上面链接中的规则3 正确处理它们。由于您没有这样做,因此无法安全地传递值。

要解决此问题,您可以按引用传递链接列表,而不是按值传递:

void checkout(linkedListU& p){

这将停止复制,但它确实没有解决未在任何类中使用的3规则的基本问题。

例如,您的puItempuItem::getFruit函数中的值返回,并且还通过puItem::setFruit函数中的值传递。在没有任何更改的情况下调用这些函数也会调用未定义的行为,因为这些类不能安全地复制(也是由于您使用了指向动态分配的内存的成员)。

要解决此问题,您可以做的第一件事是将基类item更改为使用std::string name;而不是char *name;。这使得item现在成为一个可复制的类,无需编写用户定义的复制操作或者需要delete name;的析构函数。原因是,使用std::string后,item中的所有成员都可以在没有用户干预的情况下进行复制。编译器默认版本就足够了。

class item
{
   int plu;
   std::string name;
   double price;
   double inv;

public:
    void setPLU(int g) { plu = g; }
    void setName(const char * p) { name = p; }
    void setPrice(double g) { price = g; }
    void setInventory(double g) { inv = g; }
    int getPlu() { return plu; }
    std::string getName() { return name; }
    double getPrice() { return price; }
    double getInventory() { return inv; }
};

请注意,不需要析构函数。现在,当puItem派生自此类时,puItem现在也可以安全地复制,您可以按值传递并返回puItem

class puItem : public item
{
    bool type;
    public:
        void setType(bool g) { type = g; }
        bool getType() { return type; }
};

进行这些更改完全消除了这些类的使用导致堆错误,双重删除错误或内存泄漏。有关内存问题的任何进一步错误现在都集中在您的链表类(使用动态分配的内存)上。至少,这个问题已经缩小了很多,现在已经成为焦点。