0

if I want to erase a table:

orderbook b(_self, _self.value);
auto m = b.get_index<name("idxprod")>();
for (auto &i : m) {
    m.erase(i);
}

I get the error:

Error 3160005: The table operation is not allowed Error Details: dereference of deleted object

but if I try it like this:

for (auto i = m.begin(); i != m.end();) {
    i = m.erase(i);
}

it seems to work. so my question is: why does one work but not the other?

and another thing I notice is that for (auto i : m) doesn't work... it complains:

assertion failure with message: object passed to erase is not in multi_index

which I guess means that whatever the first form of for is calling returns a reference. interestingly for (auto &i = m.begin() doesn't work either as the left value needs to be a constant, but if I for (const auto &i =, then it complains about the reassignment i = m.erase(i)

grr...

* Appendix I *

this also doesn't work:

for (auto i = m.begin(); i != m.end();) {
    m.erase(i);
    i++;
}

nor does the more normative:

for (auto i = m.begin(); i != m.end(); i++) {
    m.erase(i);
}

but curiously this does:

for (auto i = m.begin(); i != m.end();) {
    m.erase(i++);
}
1

The problem with erasing in a for loop is that you are editing the structure you are iterating over. This is not an EOS specific error.

Your first for loop creates one iterator and tries to run over your data structure. If you delete something now the references are broken. The iterator is not correctly updated and stored.

Your second suggestion is running because erase will return a correct referenced iterator and you are saving it to i = m.erase(i);. Also In every new iteration you check if the end conditions are matched which will always check for the correct last iterator element i != m.end();.

I would also suggest to take a look at my thread Delete all multi_index records without iterator? because if your multi_index is too large you won't be able to delete it anymore because the transaction time limit kicks in.

1

I use this helper function whenever I need to reset a table (mainly during development):

template<typename T>
void erase_all(T& table) {
  auto itr = table.begin();
  while(itr != table.end()) {
    itr = table.erase(itr);
  }
}

Usage: Let's say there is a table named file that you want to delete, simply call:

erase_all(file)

As mentioned by others, this will only work as long as the table contains a limited number of items as often during development.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.