How to automatically release legacy resources?
I was writing some simple code today, and rediscovered this general sort of problem, and realized I have not yet decided on an optimal solution. Given: 1) During a particular function, a type-int variable is initialized with a value corresponding to a POSIX file descriptor. 2) There are multiple paths of exit from the function, including both returns and exceptions. Problem: What is the best way to ensure that the file descriptor is automatically close()ed when the function is exited? An additional thorn is that there must be code for handling that case where close() fails. The solution must handle both cases where I'd like to throw an exception, or cases where I'd just like to print an error message and continue. I have considered various solutions, some involving throw away classes, and none of them appear to be satisfactory. So far, the best solution I have is to create a reusable helper (based on templates and boost::function) that is created as an automatic variable and is passed the file descriptor, and a functor (which may be a boost.lambda expression) that calls close(), and contains any other necessary error-processing code. But seriously, for such a simple problem, this is insane! Solutions I don't particularly like involve creating a non-reusable throw-away class that handles just this one particular case, or lack sufficient mechanisms for handling errors. Any ideas? Aaron W. LaFramboise
Aaron W. LaFramboise wrote:
I was writing some simple code today, and rediscovered this general sort of problem, and realized I have not yet decided on an optimal solution.
Given: 1) During a particular function, a type-int variable is initialized with a value corresponding to a POSIX file descriptor. 2) There are multiple paths of exit from the function, including both returns and exceptions.
Problem: What is the best way to ensure that the file descriptor is automatically close()ed when the function is exited?
Since you don't want to write a special class for RAII, it sounds like a job for scope_guard + lambda. scope_guard is currently an implementation detail in multi_index, but will soon move to detail. The lambda expressions for control stuctures http://www.boost.org/doc/html/lambda/le_in_details.html#lambda.lambda_expres... and exceptions http://www.boost.org/doc/html/lambda/le_in_details.html#lambda.exceptions should allow you to do error handling. (I don't actually use lambda, but it looks like it should work)
So far, the best solution I have is to create a reusable helper (based on templates
This sound okay.
and boost::function)
I don't see why you need boost::function
that is created as an automatic variable and is passed the file descriptor, and a functor (which may be a boost.lambda expression) that calls close(), and contains any other necessary error-processing code. But seriously, for such a simple problem, this is insane!
This is the motivation for bind, lambda and scope guard.
Solutions I don't particularly like involve creating a non-reusable throw-away class that handles just this one particular case, or lack sufficient mechanisms for handling errors.
Jonathan
Jonathan Turkanis wrote:
Since you don't want to write a special class for RAII, it sounds like a job for scope_guard + lambda. scope_guard is currently an implementation detail in multi_index, but will soon move to detail. The lambda expressions for control stuctures
scope_guard is exactly what I was looking for here. Its too bad, though, that the syntax for it really isn't that great. One thing I don't like to see in a design of a reusable component is something that requires a lot of structure that doesn't have anything to do with the problem domain. In any case, would it be possible to move scope_guard to a place where users may legitimately use it, rather than detail? Is there a particular reason that arbitrary code shouldn't use it, or that its interface may change in the future, any more than any other documented Boost interface?
I don't see why you need boost::function
The lambda expression needs to be stored somewhere. The actual automatic variable can't be templatized based on the type of the functor without being profane, so some sort of tool like boost::function or boost::any should be required. scope_guard pretty much reimplements what boost::function provides by itself. Aaron W. LaFramboise
Aaron W. LaFramboise wrote:
Jonathan Turkanis wrote:
scope_guard is exactly what I was looking for here.
Its too bad, though, that the syntax for it really isn't that great. One thing I don't like to see in a design of a reusable component is something that requires a lot of structure that doesn't have anything to do with the problem domain.
Ideally we would have built-in lamba expressions.
In any case, would it be possible to move scope_guard to a place where users may legitimately use it, rather than detail? Is there a particular reason that arbitrary code shouldn't use it, or that its interface may change in the future, any more than any other documented Boost interface?
After it's moved into detail, there will have to be a fast track review before it is an official library.
I don't see why you need boost::function
<snip>
scope_guard pretty much reimplements what boost::function provides by itself.
Boost.Function adds an extra level of indirection and possibly a dynamic allocation that isn't needed here.
Aaron W. LaFramboise
Jonathan
What is the best way to ensure that the file descriptor is automatically close()ed when the function is exited?
Hi Aaron, I would create a class (File or other name) that close() on its destructor. The constructor can take an additional boolean parameter to configure the error handling with default value to throw exception (personally I would not add that, I would always throw the exception and leave to the user to catch it if he/she wants to do so. I just mentioned it because it seems you would like the solution to handle that). This way the file would be closed upon leaving the scope. Stroustrup talks about that on his "The C++ Programming Language" 3rd ed. in 14.4.1 (page 366 on my edition) and calls it "resource acquisition is initialization". I think this can be useful and reusable. I am not familiar with boost file system library and I don't know if it has already something like this that would solve your problem. You might have thought of that already. If you did, please share your comments on why this would not be enough. Best regards, Mauricio Gomes Pensar Digital phone: 55-11-4121-6287 mobile: 55-11-8319-9610 http://pensardigital.com On Jan 21, 2005, at 6:39 PM, Aaron W. LaFramboise wrote:
I was writing some simple code today, and rediscovered this general sort of problem, and realized I have not yet decided on an optimal solution.
Given: 1) During a particular function, a type-int variable is initialized with a value corresponding to a POSIX file descriptor. 2) There are multiple paths of exit from the function, including both returns and exceptions.
Problem: What is the best way to ensure that the file descriptor is automatically close()ed when the function is exited?
An additional thorn is that there must be code for handling that case where close() fails. The solution must handle both cases where I'd like to throw an exception, or cases where I'd just like to print an error message and continue.
I have considered various solutions, some involving throw away classes, and none of them appear to be satisfactory.
So far, the best solution I have is to create a reusable helper (based on templates and boost::function) that is created as an automatic variable and is passed the file descriptor, and a functor (which may be a boost.lambda expression) that calls close(), and contains any other necessary error-processing code. But seriously, for such a simple problem, this is insane!
Solutions I don't particularly like involve creating a non-reusable throw-away class that handles just this one particular case, or lack sufficient mechanisms for handling errors.
Any ideas?
Aaron W. LaFramboise _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Mauricio Gomes wrote:
I would create a class (File or other name) that close() on its destructor.
I do not like this solution, but not because it doesn't work. It works just fine, and probably better than the more complicated alternatives that I have been thinking of. The trouble is that its 'difficult.' Writing a class to do this takes a small but significant amount of effort. Maintaining code with this class be be slightly but significantly more difficult. In particular, in code specific to a particular problem domain (as opposed to in general-purpose libraries), I don't like to see a whole lot of code that has nothing to do with that domain, or adds a whole lot of structure for very little expressive benefit. This sort of verbosity is a problem--I think--and a particular problem for C++. A significant criticism of C++ that I have heard is that the implementation of many sorts of code requires too structure, so that there is less actual expressive code than non-expressive code. Aaron W. LaFramboise
I think this should work for all the cases you mention: http://www.boost.org/libs/smart_ptr/sp_techniques.html#handle http://www.boost.org/libs/smart_ptr/sp_techniques.html#on_block_exit -delfin
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Aaron W. LaFramboise Sent: Friday, January 21, 2005 2:13 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] How to automatically release legacy resources?
Mauricio Gomes wrote:
I would create a class (File or other name) that close() on its destructor.
I do not like this solution, but not because it doesn't work. It works just fine, and probably better than the more complicated alternatives that I have been thinking of.
The trouble is that its 'difficult.' Writing a class to do this takes a small but significant amount of effort. Maintaining code with this class be be slightly but significantly more difficult.
In particular, in code specific to a particular problem domain (as opposed to in general-purpose libraries), I don't like to see a whole lot of code that has nothing to do with that domain, or adds a whole lot of structure for very little expressive benefit. This sort of verbosity is a problem--I think--and a particular problem for C++. A significant criticism of C++ that I have heard is that the implementation of many sorts of code requires too structure, so that there is less actual expressive code than non-expressive code.
Aaron W. LaFramboise _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Delfin Rojas wrote:
I think this should work for all the cases you mention:
http://www.boost.org/libs/smart_ptr/sp_techniques.html#handle
http://www.boost.org/libs/smart_ptr/sp_techniques.html#on_block_exit
Thanks for this pointer! In particular, I did not know about smart_ptr's termination functor parameter. This has very nice semantics. smart_ptr plus Boost.Lambda would be quite elegant: shared_ptr<void> s(0, if_(bind(close, file_desc) == ..., ... )); Well, sort of, anyway. :) Its too bad that noone seems interested in adding proper lambda expressions to C++. bind() in particular is a pain. Jonathan Turkanis makes an important point, though. scope_guard uses initializer lifetime rules to allow the abstract entity to live beyond the end of the definition, without having to do any extra memory allocation. I don't beleive any smart_ptr- or boost::function-based solutions will have this trait. This could be an important performance efficiency consideration when adopting an idiom to be used in general. So, I suppose, real tests are in order, to see which of these approaches really works on real compilers. Of the four sorts of solutions mentioned, only scopeguard and creating a throw-away class have any chance of being optimized out, I think. The smart_ptr syntax is probably the prettiest, but it could be even prettier if a custom class that omitted the actual pointer support was created. I'm not sure if that would be a terribly big win, though. Aaron W. LaFramboise
At Friday 2005-01-21 15:13, you wrote:
Mauricio Gomes wrote:
I would create a class (File or other name) that close() on its destructor.
I do not like this solution, but not because it doesn't work. It works just fine, and probably better than the more complicated alternatives that I have been thinking of.
The trouble is that its 'difficult.' Writing a class to do this takes a small but significant amount of effort. Maintaining code with this class be be slightly but significantly more difficult.
In particular, in code specific to a particular problem domain (as opposed to in general-purpose libraries), I don't like to see a whole lot of code that has nothing to do with that domain, or adds a whole lot of structure for very little expressive benefit. This sort of verbosity is a problem--I think--and a particular problem for C++. A significant criticism of C++ that I have heard is that the implementation of many sorts of code requires too structure, so that there is less actual expressive code than non-expressive code.
yeah? well how do you do this in any OTHER language? be _expressive_ please... enquiring minds want to know!
Aaron W. LaFramboise _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"
participants (5)
-
Aaron W. LaFramboise
-
Delfin Rojas
-
Jonathan Turkanis
-
Mauricio Gomes
-
Victor A. Wagner Jr.