Recycle template in C ++ vs Java and C #
I have some experience in Java (and recently in C #) and would like to become better acquainted with C ++. I think I know some of the basics of memory (and other resource) management differences between these languages. Perhaps this is a small question related to the use of the dispose pattern and the various functions available in those languages ββto help with it. I love what I've put together in the RAII and SBRM principles and am trying to understand them further.
Suppose I have the following class and method in Java
class Resource implements Closeable {
public void close() throws IOException {
//deal with any unmanaged resources
}
}
...
void useSomeResources() {
try(Resource resource = new Resource()) {
//use the resource
}
//do other things. Resource should have been cleaned up.
}
or a pretty close analogue of C #
class Resource : IDisposable
{
public void Dispose()
{
//deal with any unmanaged resources
}
}
...
void UseSomeResources()
{
using(var resource = new Resource())
{
//use the resource
}
//do other things. Resource should have been cleaned up.
}
Would one think that the idiom that best represents this behavior in C ++ would be the following:
class Resource {
~Resource() {
cleanup();
}
public:
void cleanup() {
//deal with any non-memory resources
}
};
...
void useSomeResources()
{
{
Resource resource;
//use the resource
}
//do other things. Stack allocated resource
//should have been cleaned up by stack unwinding
//on leaving the inner scope.
}
I donβt want, in particular, to voice disputes about which language is better, and the like, but I wonder to what extent these implementations can be compared and how reliable they are in cases where the block uses the resource is faced with exceptional circumstances. I may have completely missed the point on something, and I was never really sure about the best methods for deleting - for the sake of argument, it might be worth assuming that all destroy / destroy functions here are idempotent - and really good advice on these matters might also have attitude to this issue.
Thanks for any pointers.
source to share
This is almost a sample. You don't actually need to add the function cleanup()
: the destructor should do the cleanup.
By the way, publishing open is cleanup()
allowed for random call cleanup()
, leaving the source code in an undesirable state.
class Resource {
~Resource() {
//deal with any non-memory resources
}
}; // allways ; at the end of a class ;-)
source to share
This class (1) ,
class Resource {
~Resource() {
cleanup();
}
public:
void cleanup() {
//deal with any non-memory resources
}
};
is non-idiomatic and dangerous because (1) it provides an operation cleanup
and (2) prevents classes from being extracted from that and prevents automatic variables of that class.
Exposed cleanup
can be called at any time by any code, and after cleaning, you have an unusable zombie object . And you don't know when and if it will happen, and therefore the implementation code must check for this state. Very bad. It is on par with init
constructor functions , with only a stub constructor.
In practice, classes cannot be implemented, because in a derived class whose objects are destroyed, a call to the destructor of this class occurs, and this destructor is not available and ndash; so the code won't compile.
The correct template looks like this:
class Resource
{
public:
// Whatever, then:
~Resource()
{
// Clean up.
}
};
The destructor can still be named explicitly, but there is a strong incentive not to.
Note that with class derivation and polymorphic use, the destructor is better done virtual
. But in other cases, which would unnecessarily make the class polymorphic and therefore have a dimensional cost. So this is an engineering decision.
(1) I added the missing semicolon. It's a good idea to post real code, even for small general examples.
source to share
You already mentioned the answer, it is RAII, just like in your link.
A typical class in C ++ would have a (virtual! You forgot that) destructor:
class C {
virtual ~C { /*cleanup*/ }
};
And you control your lifetime with the usual block rules:
void f() {
C c;
// stuff
// before this exits, c will be destructed
}
In fact, languages ββlike C # and Java try to imitate their templates. Since they don't have deterministic finalizers, you need to manually release unmanaged resources (using using
and try
accordingly). However, C ++ is completely deterministic, so it's much easier to do this.
source to share
Thanks for any pointers. Ha!
On the one hand, you are referring to the Java try method with the resource method, which is a shortcut to the actual call resource.close()
. Another alternative would callresource.Dispose()
It is important to remember that the object you use in Java and C # to close objects using these interfaces requires the object and element to be closed. The file should be closed after opening. There is no way to get around this, and try to get your way out of it, will leave you high and dry for memory, and leave other applications at risk for not having access to the files you claimed to be but never closed. It is important that you provide the code to close the files.
But there are other things to get rid of when objects leave memory. When these objects leave the scope, this happens. And that when Destructor is in C ++ you are calling what you stated above.
Closeable and IDisposable are what I call Responsible classes . They go above and beyond what any normal "destructor" for a class will be when it removes objects from scope and frees the top-level memory of the pointers you have. They will also take care that you may not think about it, or perhaps potentially put the system at risk later. He loves being a father and being a good father. A father should give his children refuge, but a good father knows what is best for the child, even when the children or other caregivers do not know what is best for them.
Note that it is important that you do AutoCloseable
not need to reference interfaces Closeable
if you want to use the "try with resources" alternative in Java.
Answer. The interface IDisposable
, Closeable
and even the interface, AutoCloseable
supports support for remote managed resources. Also the C ++ "Destructor", the grandfather of shorthand for such a deletion process. The problem is that you still need to ensure that the members of your destructive class are handled correctly. I think you have the correct function to call in C ++ to do what you want to do.
Literature: http://www.completecsharptutorial.com/basic/using.php http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
source to share
To summarize some of the good questions raised in other answers to this question and some other things I've read:
- The answer to the main question: yes, an automatic local variable
resource
has its own destructor, which is called regardless of how the control leaves the block in which it is defined. In this respect, internal scoping and local allocation (usually implies stacks, not heaps, but is compiler dependent) of a variable (rather than usingnew
) is very similar to a try-with-resources block in Java or a block-block in C. #. - Unlike Java and C #, the ability to allocate objects purely local (usually means: on the stack) in C ++ means that for objects dealing with resources that need to be used safely, additional interface implementations and slightly overexposed methods public deletions are not required (and generally undesirable).
- The use of the destructor
private
,~Resource()
eliminates some risk of accidental presence of objects in unexpected states (for example, file a writer without a file descriptor), but the "unmanaged resources" is still always safe located at the object is deleted (or goes out of scope, if it is an automatic local variable as in the example question.) - Using the
public
elements of the cleanup function is still perfectly possible if needed, but this is often an unnecessary hazard. If the cleanup contributor is to be made public, the destructor itself is best, as this is an obvious "self-documenting" directive to any user that it should only be called on very rare occasions: it's better to just usedelete
or let the locally allocated object fall out of scope and let the compiler make the call calling the destructor. It also removes any confusion that a public method without a destructor can cause ("should I call this objectcleanup()
before medelete
or not?"). - If a resource object needs to be inherited, it is important to make sure that its destructor is both
virtual
(overridden) and (at least as visible as)protected
to ensure that subclasses can be disposed of properly.
- The use of the destructor
- In addition, with cleanup, implemented directly in destructors, and the semantics of destruction without garbage and a collector immediately after leaving the scope for automatic variables (and after
delete
for dynamically allocated variables ), it becomes the property and responsibility of the type itself, that it is necessarily properly disposed of, and not it can just be safely removed.
An example of a more idiomatic use of C ++:
class Resource {
//whatever members are necessary
public:
//resource acquisition for which this object is responsible should be constrained to constructor(s)
~Resource() { //or virtual ~Resource() if inheritance desired
//deal with resource cleanup
}
};
When used as suggested in the question, this approach should ensure the safe use of resources without leaks.
source to share