In C++ the destructor handles this as part of the lifespan of the object. Making users of the object encapsulating the resource handle resource cleanup is an antipattern, which is why the standard library does this for you.
In C++ the destructor handles this as part of the lifespan of the object. Making users of the object encapsulating the resource handle resource cleanup is an antipattern, which is why the standard library does this for you.
int fd = socket(...);
if (fd < 0) return false;
SCOPE_EXIT { ::close(fd); };
if (ioctl(fd, ...) != 0) return false;
if (ioctl(fd, ...) != 0) return false;
...
return true;
You could totally just write the FdWrapper class, but then you're still a user handling resource cleanup, but with more lines.Which, BTW, is exactly what folly::File does :)
Yes, and that RAII class would be reusable all of the places you need to close a file descriptor. It's even a handy place to hang more methods that work on the descriptor... for instance if you wanted to abstract those ioctls.
That's why I personally never use ScopeGuards in C++. You are correct that writing a single-use RAII class requires a few lines of extra code. However I have found that after I write such a class I often find myself using it over and over.
Otherwise it seems a lot like you can just make the call at the end of scope yourself for the same line count and _much_ more readable code.
I guess if you have multiple return paths it's more tenable to use scoped dtors for this but it all really seems questionable to me -- I can't think of a single use-case where it'd be preferable to use something like this rather than a dedicated class.
(Obviously, classic RAII has pretty much the same benefit. But it requires a whole class per type, whereas this approach has less boilerplate.)
If your application uses exceptions at all, then the time to be super-defensive about exceptions is all the time. If you don't form the habit, then you'll forget in the cases where it matters.
Plus, most programmers are pretty bad at identifying where exceptions might be thrown, because it tends to reduce to the question: "Where will my code have bugs?" Obviously, if you knew, you'd have fixed them...
> _much_ more readable code.
I'd argue that it's more readable to put state build-up and tear-down next to each other, so that future readers can see and modify them together. If you put them far apart, it's easier for them to skew.
I think life is simpler if you just adopt a blanket rule: all cleanup is done in destructors/scoped guards. Occasionally code might be slightly longer than it needs to be, but your life is simpler overall. Plus you can forget the old C rule of only one return from a function that you mentioned. (If you use exceptions anywhere then you already stopped using that rule anyway.)
typedef fdwrapper = unique_ptr<int, close>;
fdwrapper fdhandle(open(filename));Also, defer in Go always uses the function exit, not the scope. Not sure you can do that in C++. Everything seems scoped.
Maybe don't do this :-)
Typically though there are custom delete/free API calls you need to make, and to use them with unique_ptr you have to pass that function pointer in as the second argument to the unique_ptr constructor.
At the very least you should have a C++ function that gives you the unique_ptr back that does the right thing; but at that point you almost might as well just make a class and give it member functions to map the C calls.
Of course, in my C++ code I would just write a class/struct to wrap any RAII-like logic, not use a “defer”. A marginal amount of extra work that pays off in consistency and readability.