I have created a class, and according to the textbook Accelerated C++ by Andrew Koenig and Barbara E. Moo,
The work of the destructor is to do any cleanup that should be done whenever an object goes away. Typically this cleanup involves releasing resources, such as memory, that the constructor has allocated.
I am trying to write a destructor, and I'm getting confused by all the code floating out there. Sometimes a simple deconstructor like this is used ~MyIntArray() {} and sometimes there are things between the {}.
What is the rule behind putting things between the curly brackets or not? Is it just containers e.g. lists, arrays, vectors, pointers that need to be placed between the curly brackets (these are the things I see in code examples out there).
edit: this is my class in case that's needed
class msgInfo
{
public:
msgInfo();
msgInfo(int, int, int, std::string, std::list<int>);
private:
int source_id;
int dest_id;
int priority;
std::string payload;
std::list<int> nodePath;
};
Rule 1:
Rule of three in C++03 or rule of five in C++11.
If your class needs a user defined copy constructor or a copy assignment operator then it most likely needs a user defined destructor.
When do you need either of these 3?
When your class has dynamically allocated pointer members and you need to maintain lifetime of each separate from that of another instance member. For e.g: char * member.
When you manage resources. For e.g: Open file handles, mutex locks etc.
Rule 2:
If your class is intended to be used for derivation and you need polymorphic deletion of objects then you must mark the destructor in Base class as virtual.
Well, if you allocated resources dynamically (new etc..) then in the destructor you'd want to release them (delete), in your case, since all of your members are not allocated dynamically, your destructor can be empty ( or non existent).
Another note worth mentioning is, if you do end up implementing the destructor, and you plan on someone inherting your class, you should make it virtual.
It is a good programming practice to provide a destructor in your C++ program even if there is no explicit need for one. In your code you might not have any dynamic memory allocation, so the destructor provided is simply ~MyIntArray() {} without any code inside.
Please also read the Wikipedia article on Rule of Three in C++.
http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
If you don't provide a destructor, the compiler will provide one for you. This automatically-generator destructor will correctly call the destructors of all of your class's data members, such as payload etc.
If you don't need to do anything beyond that then you don't need to explicitly provide a destructor. Alternatively, an empty one would work equally well.
If, on the other hand, your constructor allocates some resources (for example, connects to a database), then typically you'd need to put some code in your destructor to release that resource (e.g. disconnect from the database). This is the standard C++ idiom used to prevent resource leaks.
Your class does not have any resources that need to be dealt with in the destructor: each type is either built-in (`int) or handles its own resources (std::string,std::list`). So you do not need to implement your own destructor. The compiler will provide one that is equivalent to the empty braces one.
You would need to implement your own if your class had resources that need dealing with: dynamically allocated objects, handles or connections to sockets, databases, reference counts, etc.
One situation where it might make sense to implement an empty destructor is when you have a class which is intended to be derived from and used polymorphically. In this case, a virtual destructor is needed (there are many SO posts about that), and it is common practice to provide an empty implementation so that derived types to not have to implement it themselves when there are no resources to deal with.
virtual ~Foo() {}
A class like this doesn't need a non-trivial destructor (one, with "things between the curly brackets").
In a destructor, you must release resources, you have "manually" allocated. For example:
if you have new/new[] in the constructor and you need to free this memory in the destructor
if you have opened a file in the constructor, close it in the destructor
if you have locked a mutex in the constructor, unlock it in the destructor
Things like this.
Also, you may need some additional logic to be implemented, when an object is being destructed. Depends on what you're trying to do.
A definition of a destructor should, as far as I know or am concerned, should always look like this:
~msgInfo() { /* free stuff */ }
A constructor on the other hand may look like this:
msgInfo(): m_var1(0), m_var2("Initialize") { /* further initialization */ }
Where what comes between : and { is member variable initialization.
In the destructor you should deallocate anything which was dynamically allocated elsewhere in the class, hence the : notation is no good, since you probably need to do delete on the objects.
In your code you might not have any dynamic memory allocation,so you don't need to provide a destructor.
Related
The rule of 5 states that if a class has a user-declared destructor, copy constructor, copy assignment constructor, move constructor, or move assignment constructor, then it must have the other 4.
But today it dawned on me: when do you ever need a user-defined destructor, copy constructor, copy assignment constructor, move constructor, or move assignment constructor?
In my understanding, implicit constructors / destructors work just fine for aggregate data structures. However, classes which manage a resource need user-defined constructors / destructors.
However, can't all resource managing classes be converted into an aggregate data structure using a smart pointer?
Example:
// RAII Class which allocates memory on the heap.
class ResourceManager {
Resource* resource;
ResourceManager() {resource = new Resource;}
// In this class you need all the destructors/ copy ctor/ move ctor etc...
// I haven't written them as they are trivial to implement
};
vs
class ResourceManager {
std::unique_ptr<Resource> resource;
};
Now example 2 behaves exactly the same as example 1, but all the implicit constructors work.
Of course, you can't copy ResourceManager, but if you want a different behavior, you can use a different smart pointer.
The point is that you don't need user-defined constructors when smart pointers already have those so implicit constructors work.
The only reason I would see to have user-defined constructors would be when:
you can't use smart pointers in some low-level code (I highly doubt this is ever the case).
you are implementing the smart pointers themselves.
However, in normal code I don't see any reason to use user-defined constructors.
Am I missing something here?
The full name of the rule is the rule of 3/5/0.
It doesn't say "always provide all five". It says that you have to either provide the three, the five, or none of them.
Indeed, more often than not the smartest move is to not provide any of the five. But you can't do that if you're writing your own container, smart pointer, or a RAII wrapper around some resource.
However, in normal code I don't see any reason to use user-defined constructors.
User provided constructor allows also to maintain some invariant, so orthogonal with rule of 5.
As for example a
struct clampInt
{
int min;
int max;
int value;
};
doesn't ensure that min < max. So encapsulate data might provide this guaranty.
aggregate doesn't fit for all cases.
when do you ever need a user-defined destructor, copy constructor, copy assignment constructor, move constructor, or move assignment constructor?
Now about rule of 5/3/0.
Indeed rule of 0 should be preferred.
Available smart-pointers (I include container) are for pointers, collections or Lockables.
But resources are not necessary pointers (might be handle hidden in an int, internal hidden static variables (XXX_Init()/XXX_Close())), or might requires more advanced treatment (as for database, an auto commit at end of scope or rollback in case of exceptions) so you have to write your own RAII object.
You might also want to write RAII object which doesn't really own resource, as a TimerLogger for example (write elapsed time used by a "scope").
Another moment when you generally have to write destructor is for abstract class, as you need virtual destructor (and possible polymorphic copy is done by a virtual clone).
The full rule is, as noted, the Rule of 0/3/5; implement 0 of them usually, and if you implement any, implement 3 or 5 of them.
You have to implement the copy/move and destruction operations in a few cases.
Self reference. Sometimes parts of an object refer to other parts of the object. When you copy them, they'll naively refer to the other object you copied from.
Smart pointers. There are reasons to implement more smart pointers.
More generally than smart pointers, resource owning types, like vectors or optional or variants. All of these are vocabulary types that let their users not care about them.
More general than 1, objects whose identity matters. Objects which have external registration, for example, have to reregister the new copy with the register store, and when destroyed have to deregister themselves.
Cases where you have to be careful or fancy due to concurrency. As an example, if you have a mutex_guarded<T> template and you want them to be copyable, default copy doesn't work as the wrapper has a mutex, and mutexes cannot be copied. In other cases, you might need to guarantee the order of some operations, do compare and sets, or even track or record the "native thread" of the object to detect when it has crossed thread boundaries.
Having good encapsulated concepts that already follow the rule of five ensures indeed that you have to worry less about it. That said if you find yourselves in a situation where you have to write some custom logic, it still holds. Some things that come to mind:
Your own smart pointer types
Observers that have to unregister
Wrappers for C-libraries
Next to that, I find that once you have enough composition, it's no longer clear what the behavior of a class will be. Are assignment operators available? Can we copy construct the class? Therefore enforcing the rule of five, even with = default in it, in combination with -Wdefaulted-function-deleted as error helps in understanding the code.
To look closer at your examples:
// RAII Class which allocates memory on the heap.
class ResourceManager {
Resource* resource;
ResourceManager() {resource = new Resource;}
// In this class you need all the destructors/ copy ctor/ move ctor etc...
// I haven't written them as they are trivial to implement
};
This code could indeed nicely be converted to:
class ResourceManager {
std::unique_ptr<Resource> resource;
};
However, now imagine:
class ResourceManager {
ResourcePool &pool;
Resource *resource;
ResourceManager(ResourcePool &pool) : pool{pool}, resource{pool.createResource()} {}
~ResourceManager() { pool.destroyResource(resource);
};
Again, this could be done with a unique_ptr if you give it a custom destructor.
Though, if your class now stores a lot of resources, are you willing to pay the extra cost in memory?
What if you first need to take a lock before you can return the resource to the pool to be recycled? Will you take this lock only once and return all resources or 1000 times when you return them 1-by-1?
I think your reasoning is correct, having good smart pointer types makes the rule of 5 less relevant. However, as indicated in this answer, there are always cases to be discovered where you'll need it. So calling it out-dated might be a bit too far, it's a bit like knowing how to iterate using for (auto it = v.begin(); it != v.end(); ++it) instead of for (auto e : v). You no longer use the first variant, up to the point, you need to call 'erase' where this suddenly does become relevant again.
The rule is often misunderstood because it is often found oversimplified.
The simplified version goes like this: if you need to write at least one of (3/5) special methods then you need to write all of the (3/5).
The actual, useful rule: A class that is responsible with manual ownership of a resource should: deal exclusively with managing the ownership/lifetime of the resource; in order to do this correctly it must implement all 3/5 special members. Else (if your class doesn't have manual ownership of a resource) you must leave all special members implicit or defaulted (rule of zero).
The simplified versions uses this rhetoric: if you find yourself in need to write one of the (3/5) then most likely your class manually manages the ownership of a resource so you need to implement all (3/5).
Example 1: if your class manages the acquisition/release of a system resource then it must implement all 3/5.
Example 2: if your class manages the lifetime of a memory region then it must implement all 3/5.
Example 3: in your destructor you do some logging. The reason you write a destructor is not to manage a resource you own so you don't need to write the other special members.
In conclusion: in user code you should follow the rule of zero: don't manual manage resources. Use RAII wrappers that already implement this for you (like smart pointers, standard containers, std::string, etc.)
However if you find yourself in need to manually manage a resource then write a RAII class that is responsible exclusively with the resource lifetime management. This class should implement all (3/5) special members.
A good read on this: https://en.cppreference.com/w/cpp/language/rule_of_three
So I have been reading about the Rule of Zero.
Simplified version: I do not understand the purpose of this rule. The rule of three and five are sort of "rule of thumbs", but I cannot see the "rule of thumb" or any other specific intentions with this rule.
Detailed version:
Let me quote:
Classes that have custom destructors, copy/move constructors or
copy/move assignment operators should deal exclusively with ownership.
Other classes should not have custom destructors, copy/move
constructors or copy/move assignment operators.
What does this mean? What do they mean by ownership, ownership of what?
They have also showed an example code(I guess it is connected to the introduction):
class rule_of_zero
{
std::string cppstring;
public:
rule_of_zero(const std::string& arg) : cppstring(arg) {}
};
What do they want to show with this, I am really lost on this one.
Also, they are also talking about the scenario when you are dealing with a polymorphic class and the destructor is being declared public and virtual and the fact that this block implicit moves. Therefore, you have to declare them all as defaulted:
class base_of_five_defaults
{
public:
base_of_five_defaults(const base_of_five_defaults&) = default;
base_of_five_defaults(base_of_five_defaults&&) = default;
base_of_five_defaults& operator=(const base_of_five_defaults&) = default;
base_of_five_defaults& operator=(base_of_five_defaults&&) = default;
virtual ~base_of_five_defaults() = default;
};
Does this mean that whenever you have a base class with a destructor that is declared both public and virtual, you really have to declare all the other special member function as defaulted? If so, I do not see why.
I know that this is a lot of confusion in one place.
The Rule of Zero
The rule of zero is another rule of thumb about how to write classes that need to use some resources like memory or other objects. In the example the dynamically allocated memory containing the characters of the string is a resource that has to be managed.
The recommendation is to let specialized classes manage resources, and do only that. In the example, std::string takes care of all the details of managing the allocated memory.
The rule emerged after the introduction of C++11, because the language and the standard library had improved, providing much better facilities to manage dynamically allocated object lifetimes (unique_ptr and shared_ptr). Also the containers now allow in-place construction, removing another reason for dynamic allocation. It should probably be seen as an update to the much older rule of three.
So if you previously would have used new in your constructor to create some member and delete in the destructor, you should now use a unique_ptr to manage the lifetime of the member, getting move construction and move assignment "for free".
Shared pointers can remember the correct destructor to call, so the common need for a virtual destructor goes away for objects that are exclusively managed via shared pointer, even if they are used polymorphically.
So basically a class that can rely on its members to do all the required actions for initialization, moving, copying and destruction should not declare any of the special member functions.
The Rule of Five
As always with C++ things are not always that simple.
As Scott Meyers pointed out, if you do have to add a destructor for whatever reason, the implicit generation of move constructors and move assignment operator are disabled, even if the compiler could generate them.
Then the compiler will happily copy your class all over the place instead of moving it which may not be what you expect. This may for example slow down your program, as more copying has to be performed. The compiler will not warn about this by default.
Therefore he recommends to explicitly specify which of the five special methods you want, in order to avoid surprises due to unrelated changes. He still recommends writing non-resource-management classes such that the defaults generated by the compiler can be used.
I'm trying to validate my understanding of C++ destructors.
I've read many times that C++ supplies a default destructor if I don't write one myself. But does this mean that if I DO write a destructor that the compiler WON'T still provide the default cleanup of stack-allocated class fields?
My hunch is that the only sane behavior would be that all class fields are destroyed no matter what, whether I provide my own destructor or not. In which case the statement I've read so many times is actually a little misleading and could be better stated as:
"Whether or not you write your own destructor, the C++ compiler always
writes a default destructor-like sequence to deallocate the member
variables of your class. You may then specify additional
deallocations or other tasks as needed by defining your own destructor"
Is this correct?
When an object is cleaned up in C++, the language will
First call the destructor for the class, then
Call the destructors for all the fields of the class.
(This assumes no inheritance; if there's inheritance, the base class is then destroyed by recursively following this same procedure). Consequently, the destructor code that you write is just custom cleanup code that you'd like to do in addition to the normal cleanup code for individual data members. You won't somehow "lose" the destructors for those objects being called as normal.
Hope this helps!
Yes -- any object contained within your object will be destroyed as part of destroying your object, even if/though your destructor does nothing to destroy them.
In fact, your destructor won't normally do anything to destroy objects contained within the object; what it typically does is destroy objects that are remotely owned via something in the object (e.g., a pointer to an object, a handle to a network or database connection, etc.)
The only exception to this that's common at all is if your object contains a buffer of some sort, and you've used placement new to construct something into that buffer. If you use placement new, you normally plan on directly invoking the dtor as well. [Note that "common" is probably overstating how often you see/use this--it's really quite uncommon, but the other possibilities are much rarer still.]
Yes. Even if you DO write a destructor, the C++ compiler will create a sequence. Consider the following code:
class foo{
int a;
}
Write a destructor that deallocates a, a stack-allocated variable... its impossible. Therefore, even if you write your own destructor, a C++ compiler MUST generate one to deallocate stack objects.
I understand that placement new calls are usually matched with explicit calls to the destructor. My question is: if I have no need for a destructor (no code to put there, and no member variables that have destructors) can I safely skip the explicit destructor call?
Here is my use case: I want to write C++ bindings for a C API. In the C API many objects are accessible only by pointer. Instead of creating a wrapper object that contains a single pointer (which is wasteful and semantically confusing). I want
to use placement new to construct an object at the address of the C object. The C++ object will do nothing in its constructor or destructor, and its methods will do nothing but delegate to the C methods. The C++ object will contain no virtual methods.
I have two parts to this question.
Is there any reason why this idea will not work in practice on any production compiler?
Does this technically violate the C++ language spec?
If I understand your question correctly you have a C object in memory and you want to initialize a C++ object with the same layout "over the top" of the existing object.
CppObject* cppobject = new (cobject) CppObject;
While there is no problem with not calling a destructor for the old object - whether this causes resource leaks or other issues is entirely down to the type of the old object and is a user code issue, not a language conformance issue - the fact that you reuse the memory for a new object means that the old object is no longer accessible.
Although the placement form of operator new must just return the address that it was given, there is nothing to stop the new expression itself wiping the memory for the new object before any constructor (if any) is called. Members of the new object that are not initialized according to C++ language rules have unspecified contents which definitely does not mean the same as having the contents of any old object that once lived in the memory being reused.
If I understand you correctly, what you are trying to do is not guaranteed to work.
I think the answer is that if your class is POD (which it is, if it's true that it does nothing in the con/destructor, has no virtual member functions, and has no non-static data members with any of those things), then you don't need to call a constructor or a destructor, its lifetime is just the lifetime of the underlying memory. You can use it the same way that a struct is used in C, and you can call its member functions regardless of whether it has been constructed.
The purpose of placement new is to allow you to create object pools or align multiple objects together in contiguous memory space as with std::vector.
If the objects are C-structs then you do not need placement new to do this, you can simply use the C method of allocating the memory based on sizeof(struct Foo) where Foo is the struct name, and if you allocate multiple objects you may need to multiple the size up to a boundary for alignment.
However there is no need to placement-new the objects there, you can simply memcpy them in.
To answer your main question, yes you still need to call the destructor because other stuff has to happen.
Is there any reason why this idea will not work in practice on any production compiler?
You had damn well be sure your C++ object fits within the size of the C object.
Does this technically violate the C++ language spec?
No, but not everything that is to spec will work like you want.
I understand that placement new calls are usually matched with explicit calls to the destructor. If I have no need for a destructor (no code to put there, and no member variables that have destructors) can I safely skip the explicit destructor call?
Yes. If I don't need to fly to New York before posting this answer, can I safely skip the trip? :) However, if the destructor is truly unneeded because it does nothing, then what harm is there in calling it?
If the compiler can figure out a destructor should be a no-op, I'd expect it to eliminate that call. If you don't write an explicit dtor, remember that your class still has a dtor, and the interesting case – here – is whether it is what the language calls trivial.
Solution: destroy previously constructed objects before constructing over them, even when you believe the dtor is a no-op.
I want to write C++ bindings for a C API. In the C API many objects are accessible only by pointer. Instead of creating a wrapper object that contains a single pointer (which is wasteful and semantically confusing). I want to use placement new to construct an object at the address of the C object.
This is the purpose of layout-compatible classes and reinterpret_cast. Include a static assert (e.g. Boost's macro, 0x static_assert, etc.) checking size and/or alignment, as you wish, for a short sanity check, but ultimately you have to know a bit of how your implementation lays out the classes. Most provide pragmas (or other implementation-specific mechanisms) to control this, if needed.
The easiest way is to contain the C struct within the C++ type:
// in C header
typedef struct {
int n;
//...
} C_A;
C_A* C_get_a();
// your C++
struct A {
void blah(int n) {
_data.num += n;
}
// convenience functions
static A* from(C_A *p) {
return reinterpret_cast<A*>(p);
}
static A const* from(C_A const *p) {
return reinterpret_cast<A const*>(p);
}
private:
C_A _data; // the only data member
};
void example() {
A *p = A::from(C_get_a());
p->blah(42);
}
I like to keep such conversions encapsulated, rather than strewing reinterpret_casts throughout, and more uniform (i.e. compare call-site for const and non-const), hence the convenience functions. It's also a bit harder to modify the class without noticing this type of use must still be supported.
Depending on the exact class, you might make the data member public.
The first question is: why don't you just use a cast? Then there's no issue of the placement new doing anything, and clearly no issue of failing to use a destructor. The result will work if the C and C++ types are layout compatible.
The second question is: what is the point? If you have no virtual functions, you're not using the constructor or destructor, the C++ class doesn't seem to offer any advantages over just using the C type: any methods you write should have been global functions anyhow.
The only advantage I can imagine is if you want to hide the C representation, you can overlay the C object with a class with all private members and use methods for access. Is that your purpose? [That's a reasonable thing to do I think]
What potential memory leaks won't an implicit destructor handle? I know that if you have anything stored on the heap it won't handle it, and if you have a connection to a file or a database, that needs to be handled manually. Is there anything else? What about, say, non-base data types like vectors?
Also, in an explicit destructor, need you destroy non-heap variables which would have been destroyed by the implicit, or are they handled automatically?
Thanks
vectors and the like will deallocate themselves because their destructor is called.
In fact your problem will lie with anything that would cause a problem of a dangling pointer (or handle or whatever), ie anything that needs to be manually Closed or de-allocated won't be in an implicit destructor. Anything that destructs itself properly will be fine. This is why the RAII idiom is so popular :)
I think the question is upside-down. Don't think in terms of what object destruction doesn't do: think in terms of what it does do.
If a class only has an implicit destructor, then when it is destroyed, all non-static data members are destroyed too, as are all base-class sub-objects.
You can argue a bit whether this is done "by the implicit destructor" or not - if you write a destructor, those things still happen. It's part of the object destruction process itself, rather than part of the code of the destructor as such.
So, if your "connection to a file" is a FILE* class member, then the default destructor doesn't release it, because FILE* is a C thing, and it doesn't have a destructor. Destroying a FILE* does nothing. If your "connection to a file" is a std::ofstream, then it does have a destructor, and the destructor tries to flush and close the connection.
Vector has a destructor which release the vector's resources. This means that in turn the elements in the vector have their destructors called.
For each member variable you have, you should look at the corresponding documentation to see how resources are handled for that type. Obviously with experience, you start to remember the answers.
If the member variable is a pointer, then the implicit destructor doesn't do anything with it. So if it points to heap-allocated memory, and this object holds the only pointer to that memory, then you need to free it to avoid a memory leak.
If you find yourself writing a destructor in C++ that needs to free more than one thing, then you've probably designed the class badly. There are almost certainly exception-safety errors elsewhere in the class: it's possible to get the code right, but if you're experienced enough to get it right then you're experienced enough to make your own life easier by designing it differently ;-). The solution is to write classes with a single responsibility -- to manage a single resource -- and use them as member variables. Or, better, to find library classes that manage the resource you're using. shared_ptr is pretty flexible.
"need you destroy non-heap variables"
There is no such thing in C++ as "heap" and "non-heap" variables. Destroying a pointer does not free the thing pointed to, for the obvious reason that nothing in the type of a pointer tells you how the thing it points to was allocated, or who "owns" it.
You need to understand three things about destructors. Say you have an object t of class T with three members.
class T
{
A a;
B b;
C c;
// ...
} t;
Destructing t ALWAYS means calling the following destructors in that order: ~T(), ~C(), ~B(), ~A(). You cannot influence these semantics. It is impossible to prevent the destruction of the members. This ALWAYS happens, no matter if you define ~T() manually or if the compiler generates it.
Implicitly generated destructors are ALWAYS a no-op. However, as stated in point 1, the destructors ~C(), ~B() and ~A() will still be executed afterwards.
The destructors of scalar types, especially C-style pointers, are ALWAYS a no-op. This is the sole reason why you almost always need to write the destructor (and the copy constructor and the assignment operator) manually when you have a C-style pointer member -- after ~T() has finished, destructing a C-style pointer member does NOTHING, so any cleanup intended on the pointees has to be done in ~T().
I hope this clears things up for you.
What potential memory leaks won't an implicit destructor handle? I know that if you have anything stored on the heap it won't handle it, and if you have a connection to a file or a database, that needs to be handled manually. Is there anything else? What about, say, non-base data types like vectors?
To put it simply, you are correct. The only thing not handled by the implicit destructor is memory allocated in the form of a pointer or another type of resource that needs to be released explicitly.
With regard to vectors or any other class type objects; all classes have a destructor which takes care of releasing their data. The destructor of an object of this type is called when it goes out of scope. All basic data types like: int, float, double, short, bool etc are released in similar fashion.
Also, in an explicit destructor, need you destroy non-heap variables which would have been destroyed by the implicit, or are they handled automatically?
The answer to this is that they are handled automatically, in fact you should never ever try to explicitly call the destructor of an object.
In an implicit destructor the following occurs:
Each of the member variables of the class have their destructors called in turn.
In an explicit destructor the following occurs:
The body of the explicit destructor is executed
Each of the member variables of the class have their destructors called in turn.
So you can see that an explicit destructor is much the same as an implicit one, except that you can take any necessary manual intervention.
Now as a bit of advice with regard to managing memory allocated objects you should pretty much always use RAII (resource acquisition is initialisation). The crux of this is smart pointers, these are pointers that are deleted correctly when they go out of scope just like non heap allocated objects. Ownership becomes an issue once you start using them but that's a story for another day. A good place to start with smart pointers is boost::shared_ptr. (btw if you haven't got on board with boost yet and you write c++ code do yourself a favour...)
The implicit destructor calls the destructor on all member variables.
If you have a raw pointer, its destructor does nothing. So if you own the memory it points to, you have to release it explicitly.
The same applies to any other resource, or any other action you wish to take not implied by the default destructor of the member variable.
The default destructors of members are still called, so vectors, auto_ptrs, files opened using std streams or other C++ libraries all get destroyed. The moral is to wrap any OS objects which need releasing in C++ classes which tidy themselves up, so that application classes don't have to worry about it.
A class' destructor will implicitely call the destructors of all non-static members, then the destructors of virtual base classes, then its own code.
If you have STL containers as class members, you don't have to do anything explicitely--they will free their own memory in their destructors.
You're already making wrong assumptions. If my class holds heap-allocated data using an std::auto_ptr<Data>, the implicit dtor will handle it. No memory will be leaked. The reason is that the implict dtor, like any other dtor, will call the dtors of all members and base classes.
Now, a good class design holds all important resources as members with proper dtors. As a result, the dtor body needs to do nothing to prevent resource leaks. Of course, there is one exception to that rule: resource managing classes themselves manage precisely one resource, and therefore clean up that one resource in their dtor.