|
|
|
|
|
by dataflow
530 days ago
|
|
> None of those are easier than not needing to do it at all though; if your functions exits are only where you specify, you can cleanup only once on those paths. Huh? I don't get it. This: stack.push_back(k);
absl::Cleanup _ = [&] { assert(stack.back() == k); stack.pop_back(); }
if (foo()) {
printf("foo()\n");
return 1;
}
if (bar()) {
printf("bar()\n");
return 2;
}
baz();
return 3;
is both easier, more readable, and more robust than: stack.push_back(k);
if (foo()) {
printf("foo()\n");
assert(stack.back() == k);
stack.pop_back();
return 1;
}
if (bar()) {
printf("bar()\n");
assert(stack.back() == k);
stack.pop_back();
return 2;
}
baz();
assert(stack.back() == k);
stack.pop_back();
return 3;
as well as: stack.push_back(k);
auto pop_stack = [&] { assert(stack.back() == k); stack.pop_back(); }
if (foo()) {
printf("foo()\n");
pop_stack();
return 1;
}
if (bar()) {
printf("bar()\n");
pop_stack();
return 2;
}
baz();
pop_stack();
return 3;
and unlike the others, it avoids repeating the same code three times.(Ironically, I missed the manual cleanups before the final returns in the last two examples right as I posted this comment. Edited to fix now, but that itself should say something about which approach is actually more bug-prone...) |
|
The gnarliest scenario I recall was a ring-buffer implementation that relied on a field always being within the valid length, and a single code path not performing a mod operation, which was only observably a problem after a specific sequence of reserving, popping, and pushing.
EDIT: oh, I think I see; is your code validating the invariant, or maintaining it?