Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > ptr in collection item

Reply
Thread Tools

ptr in collection item

 
 
tuvok
Guest
Posts: n/a
 
      06-16-2005
I have an Item object which allocates memory in its ctor
and frees it in its dtor.
I want to add such items to a vector. But the program crashes. Why?
How do I fix it?

#include <vector>

class Item
{
public:
int iId;
void* pMiscMem; // will be allocd in ctor and deallocd in dtor
Item(int AiId) : iId(AiId) { pMiscMem = malloc(1024); }
~Item() { free(pMiscMem), pMiscMem = 0; }
};

class MyColl
{
public:
std::vector<Item> v;
MyColl() {}
void Add(Item* pItem) { v.push_back(*pItem); }
};

void test_ptr_in_vector_item()
{
MyColl C;
for (int i = 0; i < 100; ++i)
C.Add(new Item(i));
}



 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      06-16-2005
tuvok wrote:
> I have an Item object which allocates memory in its ctor
> and frees it in its dtor.
> I want to add such items to a vector. But the program crashes. Why?
> How do I fix it?
>


Read about "the Rule of Three".

V


 
Reply With Quote
 
 
 
 
Jason Heyes
Guest
Posts: n/a
 
      06-16-2005
Your copy constructor (automatically generated by the compiler) does not
allocate new memory. Are you trying to use heterogeneous containers like in
Java? You should avoid this.


 
Reply With Quote
 
tuvok
Guest
Posts: n/a
 
      06-16-2005
"Victor Bazarov" wrote
> tuvok wrote:
> > I have an Item object which allocates memory in its ctor
> > and frees it in its dtor.
> > I want to add such items to a vector. But the program crashes. Why?
> > How do I fix it?
> >

> Read about "the Rule of Three".


Thank you. I did and came up with the following but it still crashes
What's missing?

class Item
{
public:
int iId;
void* pMiscMem; // will be allocd in ctor and deallocd in dtor

Item(int AiId) : iId(AiId), pMiscMem(0)
{ pMiscMem = malloc(1024); }

~Item()
{ free(pMiscMem), pMiscMem = 0; }

Item(const Item& Other)
{
free(pMiscMem);

iId = Other.iId;
pMiscMem = Other.pMiscMem;

Other.~Item();
}

const Item& operator=(const Item& Other)
{
free(pMiscMem);

iId = Other.iId;
pMiscMem = Other.pMiscMem;

Other.~Item();

return *this;
}
};

class MyColl
{
public:
std::vector<Item> v;
MyColl() {}
void Add(Item* pItem) { v.push_back(*pItem); }
};

void test_ptr_in_vector_item()
{
MyColl C;
for (int i = 0; i < 100; ++i)
C.Add(new Item(i));
}


 
Reply With Quote
 
tuvok
Guest
Posts: n/a
 
      06-16-2005
"Jason Heyes" wrote
> Your copy constructor (automatically generated by the compiler) does not
> allocate new memory. Are you trying to use heterogeneous containers like in Java?


I think not. Cf. code. The container shall contain objects of the same one type.




 
Reply With Quote
 
Jason Heyes
Guest
Posts: n/a
 
      06-16-2005
Remove 'free(pMiscMem)' in your copy constructor and all lines containing
'Other.~Item()'.


 
Reply With Quote
 
Larry I Smith
Guest
Posts: n/a
 
      06-16-2005
tuvok wrote:
> "Victor Bazarov" wrote
>>tuvok wrote:
>>>I have an Item object which allocates memory in its ctor
>>>and frees it in its dtor.
>>>I want to add such items to a vector. But the program crashes. Why?
>>>How do I fix it?
>>>

>>Read about "the Rule of Three".

>
> Thank you. I did and came up with the following but it still crashes
> What's missing?
>
> class Item
> {
> public:
> int iId;
> void* pMiscMem; // will be allocd in ctor and deallocd in dtor
>
> Item(int AiId) : iId(AiId), pMiscMem(0)
> { pMiscMem = malloc(1024); }


Try using 'new' and delete[], rather than malloc() and free()?
Why is pMiscMem "void *", what will it hold?

>
> ~Item()
> { free(pMiscMem), pMiscMem = 0; }
>
> Item(const Item& Other)
> {
> free(pMiscMem);
>
> iId = Other.iId;


> pMiscMem = Other.pMiscMem;



This is a copy constructor, you should be making
a copy of "Other" - not taking over its data.
You should replace the above line with something
like this:

pMiscMem = malloc(1024);
memcpy(pMiscMem, Other.pMiscMem, 1024);

Otherwise you'll have 2 Item objects who's pMiscMem
pointers point to the same memory block. When either
of those Item objects is destructed, the memory that
both Item.pMiscMem members point to will be deleted.
That will leave the pMiscMem of the remaining 'Item'
object pointing to memory that already been freed;
causing a crash when the 2nd Item object is destructed.



>
> Other.~Item();


Don't delete 'Other' in your copy constructor.
The purpose of the copy constructor is to make a copy
of 'Other' - and that's all.


> }
>
> const Item& operator=(const Item& Other)
> {
> free(pMiscMem);
>
> iId = Other.iId;


> pMiscMem = Other.pMiscMem;


This is an assignmet operator, you should be making
a copy of "Other" - not taking over its data.
You should replace the above line with something
like this:

pMiscMem = malloc(1024);
memcpy(pMiscMem, Other.pMiscMem, 1024);

Otherwise you'll have 2 Item objects who's pMiscMem
pointers point to the same memory block. When either
of those Item objects is destructed, the memory that
both Item.pMiscMem members point to will be deleted.
That will leave the pMiscMem of the remaining 'Item'
object pointing to memory that already been freed;
causing a crash when the 2nd Item object is destructed.

>
> Other.~Item();



Don't delete 'Other' in your assignment operator.
The purpose of the assignment operator is to make a
copy of the data from 'Other' in 'this' - and that's all.


>
> return *this;
> }
> };
>
> class MyColl
> {
> public:
> std::vector<Item> v;
> MyColl() {}
> void Add(Item* pItem) { v.push_back(*pItem); }
> };
>
> void test_ptr_in_vector_item()
> {
> MyColl C;
> for (int i = 0; i < 100; ++i)
> C.Add(new Item(i));
> }
>
>


Larry
 
Reply With Quote
 
tuvok
Guest
Posts: n/a
 
      06-16-2005
"Larry I Smith" wrote
> tuvok wrote:
> > "Victor Bazarov" wrote
> >>tuvok wrote:
> >>>I have an Item object which allocates memory in its ctor
> >>>and frees it in its dtor.
> >>>I want to add such items to a vector. But the program crashes. Why?
> >>>How do I fix it?
> >>>
> >>Read about "the Rule of Three".

> >
> > Thank you. I did and came up with the following but it still crashes
> > What's missing?
> >
> > class Item
> > {
> > public:
> > int iId;
> > void* pMiscMem; // will be allocd in ctor and deallocd in dtor
> >
> > Item(int AiId) : iId(AiId), pMiscMem(0)
> > { pMiscMem = malloc(1024); }

>
> Try using 'new' and delete[], rather than malloc() and free()?
> Why is pMiscMem "void *", what will it hold?


Nothing special. Just a sample for demo purposes.

> >
> > ~Item()
> > { free(pMiscMem), pMiscMem = 0; }
> >
> > Item(const Item& Other)
> > {
> > free(pMiscMem);
> >
> > iId = Other.iId;

>
> > pMiscMem = Other.pMiscMem;

>
>
> This is a copy constructor, you should be making
> a copy of "Other" - not taking over its data.
> You should replace the above line with something
> like this:
>
> pMiscMem = malloc(1024);
> memcpy(pMiscMem, Other.pMiscMem, 1024);
>
> Otherwise you'll have 2 Item objects who's pMiscMem
> pointers point to the same memory block. When either
> of those Item objects is destructed, the memory that
> both Item.pMiscMem members point to will be deleted.
> That will leave the pMiscMem of the remaining 'Item'
> object pointing to memory that already been freed;
> causing a crash when the 2nd Item object is destructed.


Ok, got it.
But wouldn't it be faster if 'this' would just take the resources of 'Other'
and clear them in 'Other'? IOW transferring the ownership from
'Other' to 'this'. The following solution does it this way. Is it ok to do it so,
or is there anything against it?

class Item
{
public:
int iId;
void* pMiscMem; // will be allocd in ctor and deallocd in dtor

Item(int AiId) : iId(AiId)
{
pMiscMem = malloc(1024); // just a sample for ptr usage in collection items
}

~Item()
{
if (pMiscMem)
free(pMiscMem);
ClearOwnership();
}

void ClearOwnership()
{ // just clears the resources (but does not destroy them!)
// intended especially for ptrs.
// will be called from copy_ctor, assignment_operator, and dtor
pMiscMem = 0; // setting ptrs to 0 is important
iId = 0;
}

Item(const Item& Other)
{ // The object will be created (initialized) from the other one (Other),
// Therefore the normal ctor won't be called.
// So nothing is initialized yet!
// The initialization from Other is the job of this copy constructor.

// set resources of this from Other:
iId = Other.iId;
pMiscMem = Other.pMiscMem;

// take ownership by clearing Other:
((Item*) &Other)->ClearOwnership();
}

const Item& operator=(const Item& Other)
{
// free resources of this:
free(pMiscMem);

// set resources of this from Other:
iId = Other.iId;
pMiscMem = Other.pMiscMem;

// take ownership by clearing Other:
((Item*) &Other)->ClearOwnership();

return *this;
}
};

class MyColl
{
public:
std::vector<Item> v;
MyColl() {}
void Add(Item& rItem) { v.push_back(rItem); }
};

void test_ptr_in_vector_item()
{
MyColl C;
for (int i = 1; i <= 10000; ++i)
{
Item obj(i);
C.Add(obj);
}
}


 
Reply With Quote
 
Larry I Smith
Guest
Posts: n/a
 
      06-16-2005
tuvok wrote:
> I have an Item object which allocates memory in its ctor
> and frees it in its dtor.
> I want to add such items to a vector. But the program crashes. Why?
> How do I fix it?
>
> #include <vector>
>
> class Item
> {
> public:
> int iId;
> void* pMiscMem; // will be allocd in ctor and deallocd in dtor
> Item(int AiId) : iId(AiId) { pMiscMem = malloc(1024); }
> ~Item() { free(pMiscMem), pMiscMem = 0; }
> };
>
> class MyColl
> {
> public:
> std::vector<Item> v;
> MyColl() {}
> void Add(Item* pItem) { v.push_back(*pItem); }
> };
>
> void test_ptr_in_vector_item()
> {
> MyColl C;
> for (int i = 0; i < 100; ++i)
> C.Add(new Item(i));
> }
>
>
>


There is a memory leak in the line:

C.Add(new Item(i));

You use 'new' to allocate an 'Item'.
A POINTER to that 'Item' is passed to Add() which
calls v.push_back(*pItem). push_back() makes a
COPY of it's arg (a copy of "*pItem" in this case),
then puts that copy into the vector. The original
'Item' allocated by 'new' is never deleted.
Here's one possible alternative:

void test_ptr_in_vector_item()
{
MyColl C;
Item * pItem;

for (int i = 0; i < 100; ++i)
{
pItem = new Item(i);
C.Add(pItem);
delete pItem;
}
}

The name 'test_ptr_in_vector()' is misleading.
You do not put a pointer to 'Item' (an "Item *")
in your vector; you put an actual 'Item'.

Larry
 
Reply With Quote
 
Andre Kostur
Guest
Posts: n/a
 
      06-16-2005
"tuvok" <520001085531-> wrote in
news:d8r5dg$mvd$01$:

> Ok, got it.
> But wouldn't it be faster if 'this' would just take the resources of
> 'Other' and clear them in 'Other'? IOW transferring the ownership from
> 'Other' to 'this'. The following solution does it this way. Is it ok
> to do it so, or is there anything against it?


Uh... why aren't you simply using std::auto_ptr then? Sounds like it has
all of the semantics that you're looking for...

And... any pointer with a transfer of ownership semantics is unsuitable for
putting into the standard containers (note: auto_ptr included!). You might
want to look up something like boost::shared_ptr.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Collection problems (create Collection object, add data to collection, bind collection to datagrid) Øyvind Isaksen ASP .Net 1 05-18-2007 09:24 AM
WebControl - CollectionEditor Problem. Changing id property of new added collection item causes not adding item to collection - Sergio ASP .Net Web Controls 0 05-29-2006 06:20 AM
const ptr to const ptr ? franco ziade C Programming 3 02-17-2005 04:30 AM
How to convert a double **ptr in a double const ** const ptr? Heiko Vogel C Programming 3 09-14-2004 10:23 AM
what's the difference between delete ptr and ptr=0 -dont they accomplish the same Sid C++ 5 07-29-2004 03:42 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57