 |
|
 |
Hi
i declared a map as follows: std::map m_AlphabetList;
and when i close my application (in debug mode), i found some memory leaks:
47} normal block at 0x00A41DF0, 33 bytes long.
Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD
{46} normal block at 0x00A41E40, 40 bytes long.
Data: < |L > 14 7C 4C 10 16 00 00 00 00 00 00 00 00 00 00 00
can u tell me plz what is the problem
Sami
|
|
|
|
 |
|
 |
Hi Sami,
I think you should provide more information for us such like how did you do with your m_AlphabetList, what did you add to it. Or you may find more clues from the below messages which were from actual experts.
Cheers,
Amon
|
|
|
|
 |
|
 |
Need I say more?
|
|
|
|
 |
|
 |
With people like you we would still think that earth is flat.
Jonathan de Halleux.
www.dotnetwiki.org
|
|
|
|
 |
|
 |
STL Hater wrote:
Need I say more?
No. Now sit down and write 500 times: STL is great.
|
|
|
|
 |
|
 |
The main like say the following:
std::vector< int * > vInt;
for( int i = 0 ; i < 10 ; i++ )
{
int * p = new int;
*p = i;
vInt.push_back( p );
delete p;
}
Now why the following is an address problem mainly and the object which has been allcoated on to the heap is no longer there, cause an address conflict as well. Thus accessing vInt[0-9] would throw 0xC0000005 becaue the memory address is invalid. This can be applied to structures and/or classes doesn't not matter. When object allocated with new on malloc/calloc is allocated its data is on the local heap deleting items pushed back inside scope or a local var and/or not delete pushed back view push_back( new XXX( 10 ) ); will remain allocated if not take depanding on the program could cause major affects. If i'm incorrect on this please correct but i think i'm right on track .
|
|
|
|
 |
|
 |
I am sorry. yestoday I wrote it in a hurry on the net without a check.Now I had updated it, and hope you guys give some comments to it.
Thanks
|
|
|
|
 |
|
 |
The STL does memory management correctly (if implemented correctly, of course). In the sample you're using in the article, no memory leaks can occur. Your attempt to 'help' the vector with memory management is wrong and will probably cause lots of problems, most probably crashes. In your sample you use a vector defined like this: std::vector<CObject>. This is a vector that contains instances of CObject. The memory required to store the CObjects is completely managed by the vector itself. When you remove an element, the memory required for it will be freed. Note that the memory might not be freed immediately, since the vector tries to avoid too frequent resizing of the memory it alloctes for performance reasons. Now there's a case that's a bit more complicated: Imagine a vector of type std::vector<CObject*>. In this case, the vector does not manage CObjects, but only pointers to CObjects. This means that the vector will only manage the memory required to store the pointers. It does not, however, care about whatever the pointer points to. If you remove an element out of such a vector, only the pointer will be removed (and the space required to save the pointer will be freed). The object that is pointed to by this pointer is not affected by this. If you want that object to be deleted as well (not just the pointer being removed from the vector), it's your responsibility to delete it yourself. This might be a bit confusing for people comming to STL from a Java or .NET background. In Java and .NET objects can only be accessed via references. When you have an array of objects (or a container of objects) in Java, you actually have an array of references to objects. In C++ this would be vector<object*>. There is not counterpart for C++'s vector<object> in Java. The confusion is probably caused by the syntax. If you write "Object obj" in Java, you get a reference to an Object. If you write this in C++, you get an instance of Object; the counterpart of Java's "Object obj" in C++ would be "Object* obj".
|
|
|
|
 |
|
 |
He referred to std::vector<CObject*> everywhere in the code but in the typedef.
[edit]No.. it's mixed [/edit]
--
Unser Tanz ist so wild! Ein neuer böser Tanz.
Alle gegen Alle!
|
|
|
|
 |
|
 |
I think the author meant to use CObject* because he uses delete later in his code. He really should be more careful when writing an article. I would forgive a simple mistake like that if the article was well formatted and had a good explanation, but the author forgot that too. It seems he did not really put that much effort into it.
As far as correcting the problem, one could use a container of reference counted smart pointers. (NOT auto_ptr's -- containers of auto_ptr's are explicitly forbidden by the C++ standard and for good reason [which I will not explain here]!)
|
|
|
|
 |
|
 |
I think the author meant to use CObject* because he uses delete later in his code.
He never uses new. The objects being inserted into the vector are copied from auto variables, which would cause serious problems if it was a vector of CObject *
The important principle is: If you allocate the memory, you should free it. If you didn't allocate it, it's not yours to free.
Obviously it will be different if explicitly documented, but those are exceptional cases.
|
|
|
|
 |
|
 |
Thank Rolf for your comment.
you are right ,and giving us a very good explaination to stl memory managerment topic caused by my wrong given example code.
In fact,at the beggining I just try to warn some guys like me to avoid memory problem at the situation that stl just manager the pointer.
Frenchmen say you are not a getlemen if you flirt a beautiful woman,But if you don't then you are not a man.
|
|
|
|
 |
|
 |
I write a small piece of code
std::vector sList(10);
// here we can use the stlport lib, we have the same result
//std::vector > sList(10);
//std::list sList(10);
//std::list > sList(10);
for (int i=0;i<10;i++) {
sList.push_back(i);
}
//sList.erase(sList.begin(), sList.end() );
sList.clear();
It seems this code never release all its memory. You can view the dump window to see the result
hoang. lequoc
|
|
|
|
 |
|
 |
There's nothing new there ... and bad formatting.
please, at least, reformat and "beef up" the article.
Maximilien Lincourt
Your Head A Splode - Strong Bad
|
|
|
|
 |
|
 |
Maximilien wrote:
please, at least, reformat and "beef up" the article.
I agree. This article did not teach me anything because the author did not explain how the leak occurs and how his code fixes it. A line stating "Remeber, when you delete elements from the container classes using operation such as erase(), clear() you have to delete the elements first." does not even begin to explain the situation. Also I know this is a problem with dynamically allocated objects but I question its use with static objects as the type that is held in the vector is CObject and not CObject*.
John
|
|
|
|
 |
|
 |
John M. Drescher wrote: I agree. This article did not teach me anything because the author did not explain how the leak occurs and how his code fixes it. A line stating "Remeber, when you delete elements from the container classes using operation such as erase(), clear() you have to delete the elements first." does not even begin to explain the situation. Also I know this is a problem with dynamically allocated objects but I question its use with static objects as the type that is held in the vector is CObject and not CObject*.
The problem is quite simple to explain. The STL containers will dynamically allocate memory for the object type you tell it to contain. So, if you tell it to hold type T:
std::vector TVector;
Any additions and cleanup requiring memory allocation/deallocation will set asside (or remove) space for the T object.
Now, if you change that to a T*, it will now allocate/deallocate memory for the pointer (basically, a long integer). It doesn't know (nor care) what you are putting in it, so long as the types match. Thus, it won't bother deleting your object when the vector goes out of scope.
// within some bounded scope
{
std::vector TPtrVector;
// add 3 new T* elements
TPtrVector.push_back(new T);
TPtrVector.push_back(new T);
TPtrVector.push_back(new T);
// do some cool stuff with our container
// vector cleans itself up as it goes out of scope
}
The above code will cause a memory leak. The 3 elements are created, but never destroyed. The vector will create an array of T* objects (T** if you are keeping count) and delete them when it goes out of scope. However, the T objects that the T*'s are pointing to have been created, but are never destroyed. The correct code should be:
template struct Deleter : public unary_function
{
void operator() (T x)
{
if (x != NULL)
{
delete x;
}
}
};
// within some bounded scope
{
std::vector TPtrVector;
// add 3 new T* elements
TPtrVector.push_back(new T);
TPtrVector.push_back(new T);
TPtrVector.push_back(new T);
// do some cool stuff with our container
// clean up our objects
for_each(TPtrVector.begin(), TPtrVector.end(), Deleter());
// vector cleans itself up when it goes out of scope
}
An even better solution (using TR1) would look like this:
// within some bounded scope
{
std::vector > TPtrVector;
// add 3 new T* elements
TPtrVector.push_back(std::tr1::shared_ptr(new T));
TPtrVector.push_back(std::tr1::shared_ptr(new T));
TPtrVector.push_back(std::tr1::shared_ptr(new T));
// do some cool stuff with our container
// vector cleans itself up when it goes out of scope
// shared pointers clean up correctly as vector mops up
// since the destructor is called and the reference count goes to 0
}
As for why to use T* over T ... say you have a polymorphic set of classes:
class Shape
{
public:
Shape();
virtual ~Shape();
virtual void Draw() {} // or =0; for a pure virtual
};
class Circle : public Shape
{
public:
Circle();
virtual ~Circle();
virtual void Draw() { // code to draw a circle }
};
class Square : public Shape
{
public:
Square();
virtual ~Square();
virtual void Draw() { // code to draw a square }
};
Now, if you want to store these in the same array after they are initialized, and use that array to redraw the shapes, you would need to use std::vector MyShapes;. If you just wanted to draw circles, you could have an array declared like std::vector MyCirlces;. Basically, choosing between the two depends on what they are being used for.
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
 |
|
 |
Thanks for the explanation. I use stl and know about and always remember to delete any objects I create when using pointers to objects with stl. My complaint about this article was that without reading the code I did not know what problem the author was trying to solve.
John
|
|
|
|
 |
|
 |
John M. Drescher wrote: Thanks for the explanation. I use stl and know about and always remember to delete any objects I create when using pointers to objects with stl. My complaint about this article was that without reading the code I did not know what problem the author was trying to solve.
Ah. Sorry, I misread your comment. In any case, hopefully it will be useful for someone else who reads this article and is a bit confused about it.
If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week
Zac
|
|
|
|
 |
|
 |
Zac Howland wrote: In any case, hopefully it will be useful for someone else who reads this article and is a bit confused about it.
I totally agree with that.
John
|
|
|
|
 |