I am trying to append a blank object to a list using the push_back method.
main.cpp
vector<FacialMemory> facial_memory;
printf("2\n");
// Add people face memories based on number of sections
for (int i = 0; i < QuadrantDict::getMaxFaceAreas(); i++)
{
printf("i %d\n", i);
FacialMemory n_fm;
facial_memory.push_back(n_fm); // NOTE: Breaks here
}
At the push_back method call, the program crashes with a segmentation fault. I have looked around at similar questions and they point to the solution I have here. I have also tried to pass FacialMemory() into the push_back call but still the same issue.
The FacialMemory class is defined as such:
FacialMemory.h
class FacialMemory
{
private:
vector<FaceData> face_memory;
public:
FacialMemory();
~FacialMemory();
void pushData(FaceData face);
bool isEmpty();
vector<FaceData> getFaces();
FaceData getRecent();
};
Constructor and destructor
FacialMemory::FacialMemory()
{
}
FacialMemory::~FacialMemory()
{
delete[] & face_memory;
}
When you push_back an item into a vector, the item is copied. Sometimes this triggers more work as the vector is resized: Its current contents are copied, and the now-copied elements that used to belong to the vector are destroyed. destruction invokes the destructor.
Unfortunately, FacialMemory's destructor contains a fatal error:
FacialMemory::~FacialMemory()
{
delete[] & face_memory; <<== right here
}
It tries to delete[] data that was not allocated by new[], and whatever is managing the program's memory threw a fit because the expected book-keeping structures that keep track of dynamically allocated storage (memory allocated with new or with new[]) for the storage being returned were not found or not correct.
Further, face_memory is a std::vector, an object designed to look after its memory for you. You can create, copy, resize, and delete a vector without any intervention in most cases. The most notable counter case is a vector of pointers where you may have to release the pointed-at data when removing the pointer from the vector.
The solution is to do nothing in the FacialMemory class destructor. In fact, the Rule of Zero recommends that you not have a destructor at all because FacialMemory has no members or resources that require special handling. The compiler will generate the destructor for you with approximately zero chance of a mistake being made.
While reading the link for the Rule of Zero, pay attention to the Rules of Three and Five because they handle the cases where a class does require special handling and outline the minimum handling you should provide.
One of the reason to occur Segmentation fault is when ever you access a memory part which is invalid and In your program you are deallocating memory(delete keyword in your destructor) which is not allocated by new keyword.
Please refer to vector-push-back
Try adding a meaningful copy constructor to FacialMemory class
Related
(Before anyone asks: no, i didn't forget the delete[] statement)
I was fiddling around with dinamically allocated memory and i run into this issue. I think the best way to explain it is to show you these two pieces of code I wrote. They are very similar, but in one of them my class destructor doesn't get called.
// memleak.cpp
#include <vector>
using namespace std;
class Leak {
vector<int*> list;
public:
void init() {
for (int i = 0; i < 10; i++) {
list.push_back(new int[2] {i, i});
}
}
Leak() = default;
~Leak() {
for (auto &i : list) {
delete[] i;
}
}
};
int main() {
Leak leak;
while (true) {
// I tried explicitly calling the destructor as well,
// but this somehow causes the same memory to be deleted twice
// and segfaults
// leak.~Leak();
leak = Leak();
leak.init();
}
}
// noleak.cpp
#include <vector>
using namespace std;
class Leak {
vector<int*> list;
public:
Leak() {
for (int i = 0; i < 10; i++) {
list.push_back(new int[2] {i, i});
}
};
~Leak() {
for (auto &i : list) {
delete[] i;
}
}
};
int main() {
Leak leak;
while (true) {
leak = Leak();
}
}
I compiled them both with g++ filename.cpp --std=c++14 && ./a.out and used top to check memory usage.
As you can see, the only difference is that, in memleak.cpp, the class constructor doesn't do anything and there is an init() function that does its job. However, if you try this out, you will see that this somehow interferes with the destructor being called and causes a memory leak.
Am i missing something obvious? Thanks in advance.
Also, before anyone suggests not using dinamically allocated memory: I knwow that it isn't always a good practice and so on, but the main thing I'm interested in right now is understanding why my code doesn't work as expected.
This is constructing a temporary object and then assigning it. Since you didn't write an assignment operator, you get a default one. The default one just copies the vector list.
In the first code you have:
Create a temporary Leak object. It has no pointers in its vector.
Assign the temporary object to the leak object. This copies the vector (overwriting the old one)
Delete the temporary object, this deletes 0 pointers since its vector is empty.
Allocate a bunch of memory and store the pointers in the vector.
Repeat.
In the second code you have:
Create a temporary Leak object. Allocate some memory and store the pointers in its vector.
Assign the temporary object to the leak object. This copies the vector (overwriting the old one)
Delete the temporary object, this deletes the 10 pointers in the temporary object's vector.
Repeat.
Note that after leak = Leak(); the same pointers that were in the temporary object's vector are also in leak's vector. Even if they were deleted.
To fix this, you should write an operator = for your class. The rule of 3 is a way to remember that if you have a destructor, you usually need to also write a copy constructor and copy assignment operator. (Since C++11 you can optionally also write a move constructor and move assignment operator, making it the rule of 5)
Your assignment operator would delete the pointers in the vector, clear the vector, allocate new memory to hold the int values from the object being assigned, put those pointers in the vector, and copy the int values. So that the old pointers are cleaned up, and the object being assigned to becomes a copy of the object being assigned from, without sharing the same pointers.
Your class doesn't respect the rule of 3/5/0. The default-generated move-assignment copy-assignment operator in leak = Leak(); makes leak reference the contents of the temporary Leak object, which it deletes promptly at the end of its lifetime, leaving leak with dangling pointers which it will later try to delete again.
Note: this could have gone unnoticed if your implementation of std::vector systematically emptied the original vector upon moving, but that is not guaranteed.
Note 2: the striked out parts above I wrote without realizing that, as StoryTeller pointed out to me, your class does not generate a move-assignment operator because it has a user-declared destructor. A copy-assignment operator is generated and used instead.
Use smart pointers and containers to model your classes (std::vector<std::array<int, 2>>, std::vector<std::vector<int>> or std::vector<std::unique_ptr<int[]>>). Do not use new, delete and raw owning pointers. In the exceedingly rare case where you may need them, be sure to encapsulate them tightly and to carefully apply the aforementioned rule of 3/5/0 (including exception handling).
I'm implementing a simple vector like std::vector, and I wrote some functions , without worrying what kind of exception safe guarantee it gives. I know a little about exceptions of c++, but i have not experienced writing exception safe codes.
Here is my code :
template <typename T>
class vector {
public:
vector(int _DEFAULT_VECTOR_SIZE = 10) :
size(0), array_(new T[_DEFAULT_VECTOR_SIZE]), capacity(_DEFAULT_VECTOR_SIZE) {}
void push_back(T& elem)
{
if (size == capacity)
resize(2 * size);
array_[size] = elem;
size++;
}
void pop_back()
{
--size;
}
void resize(int size_)
{
if (size_ > capacity)
{
T* temp = new T[size_];
memcpy(temp,array_,size*sizeof(T));
swap(temp, array_);
delete[] array_;
capacity = size_;
}
}
private:
T* array_;
int size;
int capacity;
};
So my question is: How can I modify my code(functions) , that would give at least basic guarantee , or some technique of writing exception safe code for basic or strong guarantee ?
Thanks
Exception-safety comes in two major flavours:
If an exception happens, your program ends in a sane state. Which one is unspecified.
If an exception happens, your program ends in the original state.
The main challenge for you will be to deal with assignment and copy constructors throwing. As the comments already note, you shouldn't use memcpy because that fails to call copy constructors. Copying a std::string should also copy the character buffer, for instance, and a vector of strings is a perfectly normal type which you should support.
So, let's look at your vector's copy constructor. It will need to copy every element of the source vector. And each individual copy can throw. What if one of the strings is so long that a copy throws std::bad_alloc ?
Now, exception safety means that you leave the program in a sane state, so no memory leaks. Your vector's copy ctor failed, so the dtor won't run. Who cleans up T* array then? This must be done in your copy ctor.
When the copy fails, there won't be a new vector, so you get the second type of exception safety for free. ("strong exception safety"). But let's look at the assignment operator next, v2 = v1. There's an old vector that you will overwrite. If you first do a .resize(0) and then copy over all elements, you may encounter an exception halfway through the copy. Your original vector content is gone, and the new content is incomplete. Still, you haven't leaked any memory yet nor have you copied half an element.
To make the assignment safe, there's a simple trick: first copy the source vector to a temporary vector. If this fails, no problem (see above). We didn't touch the destination yet. But if the assignment succeeds, we swap the array* pointers, size and capacity of the temporary and the destination vectors. Swapping pointers and swapping ints is safe (can't throw). Finally, we let the temporary vector go out of scope which destroys the old vector elements that are no longer needed.
So, by doing all the dangerous operations on temporaries, we ensure that any exception doesn't touch the original state.
You'll need to check all your methods to see if these problems can occur, but the pattern is usually similar. Don't leak array if an element copy or element assignment throws, do propagate that exception to your caller.
In general, what could cause a double free in a program that is does not contain any dynamic memory allocation?
To be more precise, none of my code uses dynamic allocation. I'm using STL, but it's much more likely to be something I did wrong than for it to be a broken implmentation of G++/glibc/STL.
I've searched around trying to find an answer to this, but I wasn't able to find any example of this error being generated without any dynamic memory allocations.
I'd love to share the code that was generating this error, but I'm not permitted to release it and I don't know how to reduce the problem to something small enough to be given here. I'll do my best to describe the gist of what my code was doing.
The error was being thrown when leaving a function, and the stack trace showed that it was coming from the destructor of a std::vector<std::set<std::string>>. Some number of elements in the vector were being initialized by emplace_back(). In a last ditch attempt, I changed it to push_back({{}}) and the problem went away. The problem could also be avoided by setting the environment variable MALLOC_CHECK_=2. By my understanding, that environment variable should have caused glibc to abort with more information rather than cause the error to go away.
This question is only being asked to serve my curiosity, so I'll settle for a shot in the dark answer. The best I have been able to come up with is that it was a compiler bug, but it's always my fault.
In general, what could cause a double free in a program that is does not contain any dynamic memory allocation?
Normally when you make a copy of a type which dynamically allocates memory but doesn't follow rule of three
struct Type
{
Type() : ptr = new int(3) { }
~Type() { delete ptr; }
// no copy constructor is defined
// no copy assign operator is defined
private:
int * ptr;
};
void func()
{
{
std::vector<Type> objs;
Type t; // allocates ptr
objs.push_back(t); // make a copy of t, now t->ptr and objs[0]->ptr point to same memory location
// when this scope finishes, t will be destroyed, its destructor will be called and it will try to delete ptr;
// objs go out of scope, elements in objs will be destroyed, their destructors are called, and delete ptr; will be executed again. That's double free on same pointer.
}
}
I extracted a presentable example showcasing the fault I made that led to the "double free or corruption" runtime error. Note that the struct doesn't explicitly use any dynamic memory allocations, however internally std::vector does (as its content can grow to accommodate more items). Therefor, this issue was a bit hard to diagnose as it doesn't violate 'the rule of 3' principle.
#include <vector>
#include <string.h>
typedef struct message {
std::vector<int> options;
void push(int o) { this->options.push_back(o); }
} message;
int main( int argc, const char* argv[] )
{
message m;
m.push(1);
m.push(2);
message m_copy;
memcpy(&m_copy, &m, sizeof(m));
//m_copy = m; // This is the correct method for copying object instances, it calls the default assignment operator generated 'behind the scenes' by the compiler
}
When main() returns m_copy is destroyed, which calls the std::vector destructor. This tries to delete memory that was already freed when the m object was destroyed.
Ironically, I was actually using memcpy to try and achieve a 'deep copy'. This is where the fault lies in my case. My guess is that by using the assignment operator, all the members of message.options are actually copied to "newly allocated memory" whereas memcpy would only copy those members that were allocated at compile time (e.g. a uint32_t size member). See Will memcpy or memmove cause problems copying classes?. Obviously this also applies to structs with non-fundamental typed members (as is the case here).
Maybe you also copied a std::vector incorrectly and saw the same behavior, maybe you didn't. In the end, it was my entirely my fault :).
It is the first time I am using STL and I am confused about how should I deallocate the the memory used by these containers. For example:
class X {
private:
map<int, int> a;
public:
X();
//some functions
}
Now let us say I define the constructor as:
X::X() {
for(int i=0; i<10; ++i) {
map[i]=i;
}
}
Now my question is should I write the destructor for this class or the default C++ destructor will take care of deallocating the memory(completely)?
Now consider the modification to above class
class X {
private:
map<int, int*> a;
public:
X();
~X();
//some functions
}
Now let us say I define the constructor as:
X::X() {
for(int i=0; i<10; ++i) {
int *k= new int;
map[i]=k;
}
}
Now I understand that for such a class I need to write a destructor as the the memory allocated by new cannot be destructed by the default destructor of map container(as it calls destructor of objects which in this case is a pointer). So I attempt to write the following destructor:
X::~X {
for(int i=0; i<10; ++i) {
delete(map[i]);
}
//to delete the memory occupied by the map.
}
I do not know how to delete the memory occupied by the map. Although clear function is there but it claims to bring down the size of the container to 0 but not necessarily deallocate the memory underneath. Same is the case with vectors too(and I guess other containers in STL but I have not checked them).
Any help appreciated.
should I write the destructor for this class or the default C++ destructor will take care of deallocating the memory(completely)?
Yes it will. All the standard containers follow the principle of RAII, and manage their own dynamic resources. They will automatically free any memory they allocated when they are destroyed.
I do not know how to delete the memory occupied by the map.
You don't. You must delete something if and only if you created it with new. Most objects have their memory allocated and freed automatically.
The map itself is embedded in the X object being destroyed, so it will be destroyed automatically, and its memory will be freed along with the object's, once the destructor has finished.
Any memory allocated by the map is the responsibility of the map; it will deallocate it in its destructor, which is called automatically.
You are only responsible for deleting the dynamically allocated int objects. Since it is difficult to ensure you delete these correctly, you should always use RAII types (such as smart pointers, or the map itself) to manage memory for you. (For example, you have a memory leak in your constructor if a use of new throws an exception; that's easily fixed by storing objects or smart pointers rather than raw pointers.)
When a STL collection is destroyed, the corresponding destructor of the contained object is called.
This means that if you have
class YourObject {
YourObject() { }
~YourObject() { }
}
map<int, YourObject> data;
Then the destructor of YourObject is called.
On the other hand, if you are storing pointers to object like in
map<int, YourObject*> data
Then the destruct of the pointer is called, which releases the pointer itself but without calling the pointed constructor.
The solution is to use something that can hold your object, like a shared_ptr, that is a special object that will care about calling the holded item object when there are no more references to it.
Example:
map<int, shared_ptr<YourObject>>
If you ignore the type of container you're dealing with an just think of it as a container, you'll notice that anything you put in the container is owned by whomever owns the container. This also means that it's up to the owner to delete that memory. Your approach is sufficient to deallocate the memory that you allocated. Because the map object itself is a stack-allocated object, it's destructor will be called automatically.
Alternatively, a best practice for this type of situation is to use shared_ptr or unique_ptr, rather than a raw pointer. These wrapper classes will deallocate the memory for you, automatically.
map<int shared_ptr<int>> a;
See http://en.cppreference.com/w/cpp/memory
The short answer is that the container will normally take care of deleting its contents when the container itself is destroyed.
It does that by destroying the objects in the container. As such, if you wanted to badly enough, you could create a type that mismanaged its memory by allocating memory (e.g., in its ctor) but doesn't release it properly. That should obviously be fixed by correcting the design of those objects though (e.g., adding a dtor that releases the memory they own). Alternatively, you could get the same effect by just storing a raw pointer.
Likewise, you could create an Allocator that didn't work correctly -- that allocated memory but did nothing when asked to release memory.
In every one of these cases, the real answer is "just don't do that".
If you have to write a destructor (or cctor or op=) it indicates you likely do something wrong. If you do it to deallocate a resource more likely so.
The exception is the RAII handler for resources, that does nothing else.
In regular classes you use proper members and base classes, so your dtor has no work of its own.
STL classes all handle themselves, so having a map you have no obligations. Unless you filled it with dumb pointers to allocated memory or something like that -- where the first observation kicks in.
You second X::X() sample is broken in many ways, if exception is thrown on the 5th new you leak the first 4. And if you want to handle that situatuion by hand you end up with mess of a code.
That is all avoided if you use a proper smart thing, like unique_ptr or shared_ptr instead of int*.
Basic Question: when does a program call a class' destructor method in C++? I have been told that it is called whenever an object goes out of scope or is subjected to a delete
More specific questions:
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
3) Would you ever want to call a destructor manually?
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
It depends on the type of pointers. For example, smart pointers often delete their objects when they are deleted. Ordinary pointers do not. The same is true when a pointer is made to point to a different object. Some smart pointers will destroy the old object, or will destroy it if it has no more references. Ordinary pointers have no such smarts. They just hold an address and allow you to perform operations on the objects they point to by specifically doing so.
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
That's up to the implementation of the linked list. Typical collections destroy all their contained objects when they are destroyed.
So, a linked list of pointers would typically destroy the pointers but not the objects they point to. (Which may be correct. They may be references by other pointers.) A linked list specifically designed to contain pointers, however, might delete the objects on its own destruction.
A linked list of smart pointers could automatically delete the objects when the pointers are deleted, or do so if they had no more references. It's all up to you to pick the pieces that do what you want.
3) Would you ever want to call a destructor manually?
Sure. One example would be if you want to replace an object with another object of the same type but don't want to free memory just to allocate it again. You can destroy the old object in place and construct a new one in place. (However, generally this is a bad idea.)
// pointer is destroyed because it goes out of scope,
// but not the object it pointed to. memory leak
if (1) {
Foo *myfoo = new Foo("foo");
}
// pointer is destroyed because it goes out of scope,
// object it points to is deleted. no memory leak
if(1) {
Foo *myfoo = new Foo("foo");
delete myfoo;
}
// no memory leak, object goes out of scope
if(1) {
Foo myfoo("foo");
}
Others have already addressed the other issues, so I'll just look at one point: do you ever want to manually delete an object.
The answer is yes. #DavidSchwartz gave one example, but it's a fairly unusual one. I'll give an example that's under the hood of what a lot of C++ programmers use all the time: std::vector (and std::deque, though it's not used quite as much).
As most people know, std::vector will allocate a larger block of memory when/if you add more items than its current allocation can hold. When it does this, however, it has a block of memory that's capable of holding more objects than are currently in the vector.
To manage that, what vector does under the covers is allocate raw memory via the Allocator object (which, unless you specify otherwise, means it uses ::operator new). Then, when you use (for example) push_back to add an item to the vector, internally the vector uses a placement new to create an item in the (previously) unused part of its memory space.
Now, what happens when/if you erase an item from the vector? It can't just use delete -- that would release its entire block of memory; it needs to destroy one object in that memory without destroying any others, or releasing any of the block of memory it controls (for example, if you erase 5 items from a vector, then immediately push_back 5 more items, it's guaranteed that the vector will not reallocate memory when you do so.
To do that, the vector directly destroys the objects in the memory by explicitly calling the destructor, not by using delete.
If, perchance, somebody else were to write a container using contiguous storage roughly like a vector does (or some variant of that, like std::deque really does), you'd almost certainly want to use the same technique.
Just for example, let's consider how you might write code for a circular ring-buffer.
#ifndef CBUFFER_H_INC
#define CBUFFER_H_INC
template <class T>
class circular_buffer {
T *data;
unsigned read_pos;
unsigned write_pos;
unsigned in_use;
const unsigned capacity;
public:
circular_buffer(unsigned size) :
data((T *)operator new(size * sizeof(T))),
read_pos(0),
write_pos(0),
in_use(0),
capacity(size)
{}
void push(T const &t) {
// ensure there's room in buffer:
if (in_use == capacity)
pop();
// construct copy of object in-place into buffer
new(&data[write_pos++]) T(t);
// keep pointer in bounds.
write_pos %= capacity;
++in_use;
}
// return oldest object in queue:
T front() {
return data[read_pos];
}
// remove oldest object from queue:
void pop() {
// destroy the object:
data[read_pos++].~T();
// keep pointer in bounds.
read_pos %= capacity;
--in_use;
}
~circular_buffer() {
// first destroy any content
while (in_use != 0)
pop();
// then release the buffer.
operator delete(data);
}
};
#endif
Unlike the standard containers, this uses operator new and operator delete directly. For real use, you probably do want to use an allocator class, but for the moment it would do more to distract than contribute (IMO, anyway).
When you create an object with new, you are responsible for calling delete. When you create an object with make_shared, the resulting shared_ptr is responsible for keeping count and calling delete when the use count goes to zero.
Going out of scope does mean leaving a block. This is when the destructor is called, assuming that the object was not allocated with new (i.e. it is a stack object).
About the only time when you need to call a destructor explicitly is when you allocate the object with a placement new.
1) Objects are not created 'via pointers'. There is a pointer that is assigned to any object you 'new'. Assuming this is what you mean, if you call 'delete' on the pointer, it will actually delete (and call the destructor on) the object the pointer dereferences. If you assign the pointer to another object there will be a memory leak; nothing in C++ will collect your garbage for you.
2) These are two separate questions. A variable goes out of scope when the stack frame it's declared in is popped off the stack. Usually this is when you leave a block. Objects in a heap never go out of scope, though their pointers on the stack may. Nothing in particular guarantees that a destructor of an object in a linked list will be called.
3) Not really. There may be Deep Magic that would suggest otherwise, but typically you want to match up your 'new' keywords with your 'delete' keywords, and put everything in your destructor necessary to make sure it properly cleans itself up. If you don't do this, be sure to comment the destructor with specific instructions to anyone using the class on how they should clean up that object's resources manually.
Pointers -- Regular pointers don't support RAII. Without an explicit delete, there will be garbage. Fortunately C++ has auto pointers that handle this for you!
Scope -- Think of when a variable becomes invisible to your program. Usually this is at the end of {block}, as you point out.
Manual destruction -- Never attempt this. Just let scope and RAII do the magic for you.
To give a detailed answer to question 3: yes, there are (rare) occasions when you might call the destructor explicitly, in particular as the counterpart to a placement new, as dasblinkenlight observes.
To give a concrete example of this:
#include <iostream>
#include <new>
struct Foo
{
Foo(int i_) : i(i_) {}
int i;
};
int main()
{
// Allocate a chunk of memory large enough to hold 5 Foo objects.
int n = 5;
char *chunk = static_cast<char*>(::operator new(sizeof(Foo) * n));
// Use placement new to construct Foo instances at the right places in the chunk.
for(int i=0; i<n; ++i)
{
new (chunk + i*sizeof(Foo)) Foo(i);
}
// Output the contents of each Foo instance and use an explicit destructor call to destroy it.
for(int i=0; i<n; ++i)
{
Foo *foo = reinterpret_cast<Foo*>(chunk + i*sizeof(Foo));
std::cout << foo->i << '\n';
foo->~Foo();
}
// Deallocate the original chunk of memory.
::operator delete(chunk);
return 0;
}
The purpose of this kind of thing is to decouple memory allocation from object construction.
Remember that Constructor of an object is called immediately after the memory is allocated for that object and whereas the destructor is called just before deallocating the memory of that object.
Whenever you use "new", that is, attach an address to a pointer, or to say, you claim space on the heap, you need to "delete" it.
1.yes, when you delete something, the destructor is called.
2.When the destructor of the linked list is called, it's objects' destructor is called. But if they are pointers, you need to delete them manually.
3.when the space is claimed by "new".
Yes, a destructor (a.k.a. dtor) is called when an object goes out of scope if it is on the stack or when you call delete on a pointer to an object.
If the pointer is deleted via delete then the dtor will be called. If you reassign the pointer without calling delete first, you will get a memory leak because the object still exists in memory somewhere. In the latter instance, the dtor is not called.
A good linked list implementation will call the dtor of all objects in the list when the list is being destroyed (because you either called some method to destory it or it went out of scope itself). This is implementation dependent.
I doubt it, but I wouldn't be surprised if there is some odd circumstance out there.
If the object is created not via a pointer(for example,A a1 = A();),the destructor is called when the object is destructed, always when the function where the object lies is finished.for example:
void func()
{
...
A a1 = A();
...
}//finish
the destructor is called when code is execused to line "finish".
If the object is created via a pointer(for example,A * a2 = new A();),the destructor is called when the pointer is deleted(delete a2;).If the point is not deleted by user explictly or given a new address before deleting it, the memory leak is occured. That is a bug.
In a linked list, if we use std::list<>, we needn't care about the desctructor or memory leak because std::list<> has finished all of these for us. In a linked list written by ourselves, we should write the desctructor and delete the pointer explictly.Otherwise, it will cause memory leak.
We rarely call a destructor manually. It is a function providing for the system.
Sorry for my poor English!