简体   繁体   English

在 While 循环中间抛出 Std::bad_alloc

[英]Std::bad_alloc thrown in the middle of While Loop

I'm writing a function that handles an order input file (csv) using a while loops to iterate though it.我正在编写一个 function 来处理订单输入文件 (csv),它使用 while 循环对其进行迭代。

762212,1,2020-03-15,10951-3,64612-2,57544-1,80145-1,27515-2,16736-1,79758-2,29286-2,51822-3,39096-1,32641-3,63725-3,64007-2,23022-1,16974-3,26860-2,75536-2,26461-1
1,373975319551257,12-2023
258572,2,2020-03-15,96497-1,70616-1,80237-2,22248-2,56107-1,59695-1,37948-3,21316-3,63498-1,18329-1,56833-1,66295-1,47680-3,30346-1
1,201741963232463,02-2022
857003,3,2020-03-15,16655-1,88019-3,75069-3,96017-2,46883-2,15138-1,77316-1,70063-3,54452-3,86429-2,15134-2,60176-1,12946-3
2,cfeeham3s
747893,4,2020-03-17,48520-1,93268-2,63636-1,23750-2,99771-3,83203-1,21316-3,89921-2,15134-3,82831-1,30346-2,54044-3,28561-1,14792-2,23523-3,56826-2
1,3571379825697064,04-2025

Every two lines represents an input.每两行代表一个输入。 I have the following function that handles this input:我有以下处理此输入的 function:

list<Order> orders;

void read_orders(string file_name) {
    fstream read_file;
    read_file.open(file_name, ios::in);
    if (read_file.is_open()) {
        string s;
        int line_num = 1; // keeps track of line number in input file
        int o_id;
        string o_date;
        int c_id;
        vector<LineItem> itms;
        while (getline(read_file, s)) {
            cout << orders.size();        // shows that only two objects are added before failure
            if (line_num % 2 == 1) {      // handle odd numbered lines of input
                auto data = split(s, ',');
                int o_id = stoi(data[0]);
                string o_date = data[1];
                int c_id = stoi(data[2]);
                vector<LineItem> itms;
                // get line items
                int n_line_items = data.size() - 3;
                vector<string> end_data(data.end() - n_line_items, data.end());
                for (string x: end_data) {
                    auto parts = split(x, '-');
                    LineItem* it = new LineItem(stoi(parts[0]), stoi(parts[1]));
                    itms.push_back(*it);
                    delete it;
                }
            } else {                       // handle even numbered lines of input
                auto data = split(s, ',');
                Credit* pay_credit = new Credit(0.0, data[1], data[2]);  // initialize each type of payment
                PayPal* pay_paypal = new PayPal(0.0, data[1]);
                WireTransfer* pay_wire = new WireTransfer(0.0, data[1], data[2]);
                if (data[0] == "1") {
                    Order* ordr = new Order(o_id, o_date, c_id, itms, *pay_credit);
                    orders.push_back(*ordr);
                    delete ordr;
                } else if (data[0] == "2") {
                    Order* orr = new Order(o_id, o_date, c_id, itms, *pay_paypal);
                    orders.push_back(*orr);
                    delete orr;
                } else if (data[0] == "3") {
                    Order* odr = new Order(o_id, o_date, c_id, itms, *pay_wire);
                    orders.push_back(*odr);
                    delete odr;
                }
                delete pay_credit;  // trying to clean up memory
                delete pay_paypal;
                delete pay_wire;
            }

            line_num += 1;
        }
        read_file.close();
    }
}

Because of my cout statement, I can tell that it only adds two items to the list before running into the std::bad_alloc error.由于我的 cout 语句,我可以说它在遇到 std::bad_alloc 错误之前只将两项添加到列表中。 It seems to happen when it switches from adding a Credit object to adding a PayPal object into the Order(...) when it's initialized.当它在初始化时从添加Credit object 切换到添加PayPal object 到Order(...)中时,似乎会发生这种情况。 I did a lot of research into why this might happen, so I tried to clean up as much as I knew how to (I'm new to C++) but the same error kept popping up.我对为什么会发生这种情况进行了大量研究,因此我尝试尽可能多地进行清理(我是 C++ 新手),但同样的错误不断出现。 Does the error happen when I'm adding things to the list or is it when I'm creating these new objects?/How could I fix something like that?当我向列表中添加东西时是否会发生错误,或者是在创建这些新对象时发生错误?/我该如何解决这样的问题?

Here are my class definitions in case that's important:这是我的 class 定义,以防万一这很重要:

class Payment {
public:
    double amount;
    string print_detail() {
        return "hey";
    };
};

class Credit: public Payment {
private:
    string card_number;
    string expiration;
public:
    Credit(double amt, string cn, string exp) {
        this->amount = amt;
        this->card_number = cn;
        this->expiration = exp;
    }
    string print_detail() {
        return "Credit card " + this->card_number + ", exp. " + this->expiration;
    }
};

class PayPal: public Payment {
private:
    string paypal_id;
public:
    PayPal(double amt, string pp_id) {
        this->amount = amt;
        this->paypal_id = pp_id;
    }
    virtual string print_detail() {
        return "Paypal ID: " + this->paypal_id;
    }
};

class WireTransfer: public Payment {
private:
    string bank_id;
    string account_id;
public:
    WireTransfer(double amt, string b_id, string a_id) {
        this->amount = amt;
        this->bank_id = b_id;
        this->account_id = a_id;
    }
    string print_detail() {
        return "Wire transfer from Bank ID " + this->bank_id + ", Account# " + this->account_id;
    }
};

class LineItem {
private:
    int item_id;
    int qty;
public:
    LineItem(int i_id, int qt) {
        this->item_id = i_id;
        this->qty = qt;
    }
    double subtotal() {
        double subtot = 0.0;
        for (auto x: items) {
            if (x.item_id == this->item_id) {
                subtot += x.price * this->qty;
            }
        }
        return subtot;
    };
};

class Order {
private:
    int order_id;
    string order_date;
    int cust_id;
    vector<LineItem> line_items;
    Payment payment;
public:
    Order(int o_id, string o_date, int c_id, vector<LineItem> li, Payment pay) {
        this->order_id = o_id;
        this->order_date = o_date;
        this->cust_id = c_id;
        this->line_items = li;
        this->payment = pay;
    }
    string pay_type = "";

    double total() {
        double result = 0.0;
        for (auto li: line_items) {
            result += li.subtotal();
        }
        return result;
    }
    string print_order() {
        string text = "===========================\nOrder #";
        text += to_string(this->order_id) + ", Date: " + this->order_date + "\nAmount: $";
        text += to_string(this->total()) + ", Paid by ";
        text += payment.print_detail();
        return text;
    }
};

And this was the error message showing that it did insert two items:这是错误消息,表明它确实插入了两个项目:

001122terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Process returned 3 (0x3)

std::bad_alloc is often thrown when there is not enough memory to be allocated.当没有足够的 memory 可以分配时,通常会抛出std::bad_alloc I can't say if this will solve the problem, but your repeated allocations and deallocations of objects are both unnecessary and harmful (causing memory fragmentation).我不能说这是否会解决问题,但是您重复分配和释放对象既不必要又有害(导致 memory 碎片)。

Instead of代替

LineItem* it = new LineItem(stoi(parts[0]), stoi(parts[1]));
itms.push_back(*it);
delete it;

you should do你应该做

itms.push_back(LineItem(stoi(parts[0]), stoi(parts[1]));

or或者

itms.emplace_back(stoi(parts[0]), stoi(parts[1]));

The same applies to every occurence of new in read_orders .这同样适用于read_orders中每次出现的new You don't need any of them.你不需要它们中的任何一个。


Another helpful thing you can do is to preallocate memory for std::vector .您可以做的另一件有用的事情是为std::vector预分配 memory 。 If you don't know how many items it will have, do an educated guess (100, 1000, 10000, etc.).如果您不知道它将有多少项目,请进行有根据的猜测(100、1000、10000 等)。

itms.reserve(1000); //before you start to push_back() to it

Also, make sure to std::move your vectors if you want to transfer the whole content of it and not make a copy.此外,如果您想传输矢量的全部内容而不是复制,请确保std::move您的矢量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM