I'm having trouble figuring out how to delete an item from a list.
Please note that I would like to perform the deletion from the advance()
function. This code is just boiled down from my actual project, to try to isolate the error.
#include <iostream>
#include <list>
#include <iterator>
#include <algorithm>
using namespace std;
const int SCT_OSC_FILLED = 11;
class OrderInfo {
private:
std::string id;
public:
OrderInfo(std::string a, int aStatusCode);
std::string key();
int statusCode;
};
OrderInfo::OrderInfo(std::string a, int aStatusCode) {
id = a;
statusCode = aStatusCode;
}
std::string OrderInfo::key() {
return id;
}
std::list <OrderInfo> MasterOrders;
void testList();
void add(OrderInfo ordInfo);
void advance(OrderInfo ordInfo, std::list <OrderInfo> ::iterator& orderIter);
void testList() {
OrderInfo o1("1", 15);
OrderInfo o2("2", 16);
OrderInfo o3("3", SCT_OSC_FILLED);
OrderInfo o4("4", 17);
OrderInfo o5("5", SCT_OSC_FILLED);
OrderInfo o6("6", 18);
add(o1);
add(o1);
add(o2);
add(o3);
add(o4);
add(o5);
add(o6);
for (auto v : MasterOrders)
std::cout << v.key() << "\n";
}
void add(OrderInfo ordInfo) {
// Add to MasterOrders (if not already in list)
bool alreadyInList = false;
std::list <OrderInfo> ::iterator orderIter = MasterOrders.begin();
while (orderIter != MasterOrders.end())
{
OrderInfo oi = *orderIter;
alreadyInList = ordInfo.key() == oi.key();
if (alreadyInList) break;
advance(ordInfo, orderIter);
}
if (!alreadyInList) MasterOrders.push_front(ordInfo);
}
void advance(OrderInfo ordInfo, std::list <OrderInfo> ::iterator& orderIter) {
bool iterate = true;
if (ordInfo.statusCode == SCT_OSC_FILLED) {
orderIter = MasterOrders.erase(orderIter ); // https://stackoverflow.com/a/5265561/270143
iterate = false;
}
if (iterate) orderIter ;
}
int main()
{
testList();
return 0;
}
update: I forgot to state the actual goal
my goal is to just delete SCT_OSC_FILLED
ordInfo
s from within the advance()
method (that part is important) and leave the rest. My actual project code does more than what is shown, these names of functions are just made up for this example.. there is more code in them not directly related to manipulating the list (but related to processing OrderInfo
) in my actual project. My goal is to leave one copy of o1
in the list as well as o2
, o4
and o6
- removing o3
and o5
because they have an SCT_OSC_FILLED
OrderInfo.statusCode
CodePudding user response:
So the problem is nothing to do with deletion from a list. Your logic is simply wrong given the stated goal.
You want to delete all SCT_OSC_FILLED
items from the list when adding an item but the code you write deletes all items from the list when you add an item with SCT_OSC_FILLED
. You are simply testing the wrong thing.
Change this
void advance(OrderInfo ordInfo, std::list <OrderInfo> ::iterator& orderIter) {
bool iterate = true;
if (ordInfo.statusCode == SCT_OSC_FILLED) {
orderIter = MasterOrders.erase(orderIter );
iterate = false;
}
if (iterate) orderIter ;
}
to this
void advance(OrderInfo ordInfo, std::list <OrderInfo> ::iterator& orderIter) {
bool iterate = true;
if (orderIter->statusCode == SCT_OSC_FILLED) {
orderIter = MasterOrders.erase(orderIter);
iterate = false;
}
if (iterate) orderIter ;
}
Once you make that change you can see that the ordInfo
parameter is unused. Add bit more cleanup and you end up with this much simpler function
void advance(std::list <OrderInfo> ::iterator& orderIter) {
if (orderIter->statusCode == SCT_OSC_FILLED) {
orderIter = MasterOrders.erase(orderIter);
}
else {
orderIter ;
}
}
CodePudding user response:
According to cppreference.com, "References and iterators to the erased elements are invalidated." You should get an iterator to the next element, before deleting the current element.
In the same page, cppreference gives an example:
// Erase all even numbers (C 11 and later)
for (std::list<int>::iterator it = c.begin(); it != c.end(); ) {
if (*it % 2 == 0) {
it = c.erase(it);
} else {
it;
}
}
erase returns an iterator to the next element (end() if the removed element was the last), so "it = c.erase(it);" makes "it" to point to the next element, and there is no need for incrementing the iterator (with ).
So you could have something like:
void advance(OrderInfo ordInfo, std::list <OrderInfo> ::iterator& orderIter) {
if (ordInfo.statusCode == SCT_OSC_FILLED) {
orderIter = MasterOrders.erase(orderIter);
} else {
orderIter ;
}
}