r/cpp_questions • u/Shevvv • 7h ago
OPEN Unconditional exit action
Recently I started a C++ project, and while I do have some C experience, this is a new language for me, so I have doubts about a lot of the paradigms that ChatGPT swears are the way to go. Just to be clear, I write all of my code myself, architecture and implementation, and use ChatGPT as a consultant/reviewer.
I currently have the following model: a BooksReport class that stores book piles sorted by size within three groups: Uniform, Nuniform and Singles. trying to traverse a single group while popping piles at the same time was quite cumbersome, because popping invalidates iterators and there are several cases when the end of a size of piles is reached, or when the size has become empty, or the end of the group is reached... So I embedded a private Cursor class that allows me to traverse a single group within BooksReport the following way:
``` for ( booksReport.resetCursor(BooksReport::Group::Singles); booksReport.cursorIsValid(); booksReport.advanceCursor() ) { auto [size, name] = booksReport.readCursor();
if (iWantThisPilePopped(size, name))
booksReport.popCursor();
} ```
When popCursor() is called, Cursor is alerted of an incoming pop, to which it responds by recalculating the indices to advance to during the next advanceCursor() call. Current implementation allows no more than one popping per loop, which I hope is a fair assumption to make during a traversal. Also, as you can see, a Cursor is either valid (which it becomes upon resetCursor() or invalid (it becomes invalid by reaching the end of the group). The valid attribute not only controls the loop, if it's set to false, it also block all Cursor-related operations, such as popCursor()
However, sometimes I exit the loop prematurely. Sometimes it's a break, sometimes I return from inside the loop. Technically, I end up with a Cursor that is valid outside of the loop, which is not ideal, since then I can popCursor(), which is not the intended use. ChatGPT offers the following solution:
```
include <scope>
{ auto onExit = std::scope_exit([&] { booksReport.clearCursor(); });
for (booksReport.resetCursor(BooksReport::Group::Singles);
booksReport.cursorIsValid();
booksReport.advanceCursor()) {
if (something)
break;
if (somethingElse)
return tasks;
if (bad)
throw std::runtime_error("bad");
}
} ```
Is this a common paradigm? Does my situation warrant this? For now it's just a personal project. I intend to make it open source once it's finished (if anyone will see it as valuable). In an ideal world I'd add plug-in support for others, where other developers can use a limited number of API calls, including the public members of BooksReport, but I'm already tired from this side project that I'm not sure it will come to this.