For my engine, I wrote an ObjectList class that handles this pretty nicely. The idea is that changes (added/removed objects) only become "visible" after performing a manual sync on the list object for performance and consistency reasons. Generally one would perform the sync between each iteration. Syncing inside an iteration will lead to undefined behavior.
Marking an object for release adds its index as a value to the "objects needing release" table. During the sync, any objects that have been marked for release get nil'd out in the table, and only afterward does the list get re-compacted. I manually compact the list myself, rather than relying on table.remove(). In fact, the code doesn't use any table.* functions!
I tested the thing on removing 20,000 objects (the current hard object limit in my engine) and they all went poof without a hitch.
Only thing it doesn't do currently is sorting, though I imagine that might be pretty easy to add in...?
The code for it is here (though it's old and could use some cleanup - I'm pretty sure _count and _releaseListEmpty aren't actually necessary):
https://github.com/dattorz/klua/blob/ma ... ctlist.lua
You are free to use it; just don't claim it as your own.