Std::bad_alloc 在 While 循环中间抛出
Std::bad_alloc thrown in the middle of While Loop
我正在编写一个处理订单输入文件 (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
每两行代表一个输入。我有以下处理此输入的函数:
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();
}
}
由于我的 cout 语句,我可以看出它只在 运行 到 std::bad_alloc 错误之前将两项添加到列表中。当它在初始化时从添加 Credit
对象切换到将 PayPal
对象添加到 Order(...)
时,似乎会发生这种情况。我对为什么会发生这种情况进行了大量研究,所以我尽可能多地尝试清理(我是 C++ 的新手),但同样的错误不断出现。错误是在我向列表中添加内容时发生的,还是在我创建这些新对象时发生的?/我该如何解决类似的问题?
以下是我的 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;
}
};
这是显示它确实插入了两项的错误消息:
001122terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Process returned 3 (0x3)
std::bad_alloc
通常在没有足够的内存分配时抛出。我不能说这是否会解决问题,但是您重复分配和释放对象既不必要又有害(导致内存碎片)。
而不是
LineItem* it = new LineItem(stoi(parts[0]), stoi(parts[1]));
itms.push_back(*it);
delete it;
你应该做的
itms.push_back(LineItem(stoi(parts[0]), stoi(parts[1]));
或
itms.emplace_back(stoi(parts[0]), stoi(parts[1]));
这同样适用于 read_orders
中出现的每个 new
。你不需要它们中的任何一个。
您可以做的另一件有用的事情是为 std::vector
预分配内存。如果您不知道它将包含多少项,请进行有根据的猜测(100、1000、10000 等)。
itms.reserve(1000); //before you start to push_back() to it
此外,如果您想传输其全部内容而不是制作副本,请确保 std::move
您的载体。
我正在编写一个处理订单输入文件 (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
每两行代表一个输入。我有以下处理此输入的函数:
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();
}
}
由于我的 cout 语句,我可以看出它只在 运行 到 std::bad_alloc 错误之前将两项添加到列表中。当它在初始化时从添加 Credit
对象切换到将 PayPal
对象添加到 Order(...)
时,似乎会发生这种情况。我对为什么会发生这种情况进行了大量研究,所以我尽可能多地尝试清理(我是 C++ 的新手),但同样的错误不断出现。错误是在我向列表中添加内容时发生的,还是在我创建这些新对象时发生的?/我该如何解决类似的问题?
以下是我的 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;
}
};
这是显示它确实插入了两项的错误消息:
001122terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Process returned 3 (0x3)
std::bad_alloc
通常在没有足够的内存分配时抛出。我不能说这是否会解决问题,但是您重复分配和释放对象既不必要又有害(导致内存碎片)。
而不是
LineItem* it = new LineItem(stoi(parts[0]), stoi(parts[1]));
itms.push_back(*it);
delete it;
你应该做的
itms.push_back(LineItem(stoi(parts[0]), stoi(parts[1]));
或
itms.emplace_back(stoi(parts[0]), stoi(parts[1]));
这同样适用于 read_orders
中出现的每个 new
。你不需要它们中的任何一个。
您可以做的另一件有用的事情是为 std::vector
预分配内存。如果您不知道它将包含多少项,请进行有根据的猜测(100、1000、10000 等)。
itms.reserve(1000); //before you start to push_back() to it
此外,如果您想传输其全部内容而不是制作副本,请确保 std::move
您的载体。