-
November 12th, 2003, 04:57 AM
#1
basic question
Hello,
I have a hash map with int as a key and struct myStruct as the data.
I got to the conclusion that I shuold have a pointer to the struct since I have some copy operation,
this is how I define my table:
typedef std::hash_map<int, myStruct*> myStructTable;
myStructTable m_MyTable;
I have a loop that on compilation time, number of iteration is unknown. (loop on std::list)
on this loop I create on every iteration MyStruct
should I create it on advance as pointer to myStructTable and allocate it with a new
or can I creare MyStruct itself and put its address in the table
what I mean:
option 1: (no need to worry about deallocations)
for(;
{
MyStruct myStruct;
....
//my struct initialization
m_MyTable[key] = &myStruct
}
option2: (deallocate my hash_map items at the destructor (m_MyTable is a class member)
for(;
{
MyStruct *myStruct;
....
//my struct initialization
m_MyTable[key] = myStruct
}
thanks
-
November 12th, 2003, 05:33 AM
#2
Option 1 will not work, your map will point to invalid memory as soon as you will exit your initialization loop.
Option 2 will work, but that is right you will have to free your items in destructor.
I propose an option 3:
typedef std::hash_map<int,std::auto_ptr<MyStruct>> myStructTable;
std::auto_ptr<MyStruct> myStruct(new MyStruct);
// init my struct
m_MyTable[key] = myStruct;
// no need to worry about destruction (will be done by auto ptr)
// and address are on the heap (and not on the stack) --> still valid after init loop exit.
-
November 12th, 2003, 05:41 AM
#3
thanks for option 3, i guess I'll use it
but can you please tell me why in option 1, it will point to invalid memeory?
thanks
-
November 12th, 2003, 05:41 AM
#4
auto_ptr can not be used in containers. Any standard complient
compiler should not even compile code that has containers
of auto_ptrs.
If you want to put smart pointers into a container, then
use reference counted pointers.
Wakeup in the morning and kick the day in the teeth!! Or something like that.
"i don't want to write leak free code or most efficient code, like others traditional (so called expert) coders do."
-
November 12th, 2003, 06:07 AM
#5
auto_ptr can not be used in containers. Any standard complient
Oh Really ? Why not ?
Is it not possible using typedef like this:
Code:
typedef struct
{
int x;
int y;
} mystruct_t;
typedef std::auto_ptr<mystruct_t> mystruct_autoptr_t;
typedef std::hash_map<int,mystruct_autoptr_t> myStructTable;
Does I miss something ?
but can you please tell me why in option 1, it will point to invalid memory?
Because in option 1, your structs are allocated on the heap, and they will be deallocated when your init method will exit, meaning that the address you copy into your hash map will point to an invalid address.
-
November 12th, 2003, 06:09 AM
#6
Oops mistake !
Please replace:
Because in option 1, your structs are allocated on the heap, and they will be deallocated when your init method will exit, meaning that the address you copy into your hash map will point to an invalid address.
by this:
Because in option 1, your structs are allocated on the STACK, and they will be deallocated when your init method will exit, meaning that the address you copy into your hash map will point to an invalid address.
-
November 12th, 2003, 06:25 AM
#7
Originally posted by pdurye
Does I miss something ?
Oh yes, you missed something. copying auto_ptrs transfers
ownership of the object pointed to and sets the copied auto_ptr
to null. Using containers of auto_ptrs can lead to all sorts
of bad, bad behavior. I suggest you go look it up. Now since the
op is "required" to use all sorts of bad programming techniques
maybe he should toss some containers of auto_prts in there
just to make it complete.
Wakeup in the morning and kick the day in the teeth!! Or something like that.
"i don't want to write leak free code or most efficient code, like others traditional (so called expert) coders do."
-
November 12th, 2003, 06:41 AM
#8
pdurye
I read your explanatin about option 1, but then I don't understand something else
suppouse I'm not using pointer to MyStruct meaning, I'll use
typedef std::hash_map<int, myStruct> myStructTable;
myStructTable m_MyTable;
and the loop:
for(;
{
MyStruct myStruct;
....
//my struct initialization
m_MyTable[key] = myStruct
}
then isn't mystruct is also invalid after finishing the loop?
pls explain to me, becuase that's what used at the begining, when I thought no copy operation needed, so I didn't use pointers, and it worked fine, and I don't understand why (I mean after reading your explanation about option 1, this is on the stack too!)
-
November 12th, 2003, 07:31 AM
#9
then isn't mystruct is also invalid after finishing the loop?
pls explain to me, becuase that's what used at the begining, when I thought no copy operation needed, so I didn't use pointers, and it worked fine, and I don't understand why (I mean after reading your explanation about option 1, this is on the stack too!)
calling this:
Code:
m_MyTable[key] = myStruct
the copy constructor of myStruct is called and the newly created object is stored into the map. Consequenly myStruct will be destroyed when init loop will exit, but its copy will remain inside the map and will persist as long as the class to which it belongs to will persist (stack or heap depends on how you create the embedding object - on the stack or on the heap -).
As the map will call destructor of its elements you do not need to take care of freeing them. It will just be more time consuming (but if your struct is small or init called a few time do not care of this).
-
November 12th, 2003, 07:34 AM
#10
thanks
-
November 12th, 2003, 08:05 AM
#11
Oh yes, you missed something. copying auto_ptrs transfers
ownership of the object pointed to and sets the copied auto_ptr
to null. Using containers of auto_ptrs can lead to all sorts
of bad, bad behavior. I suggest you go look it up. Now since the
op is "required" to use all sorts of bad programming techniques
maybe he should toss some containers of auto_prts in there
just to make it complete.
OK see what you mean. We can get behavior problem due to the fact that copy constructor of auto_ptr is not const for the original. You are right, it was a bad idea. Thanks for explanation.
-
November 12th, 2003, 08:13 AM
#12
No, it was a good idea. If pointers must be used then a container
of smart pointers is the right solution. It is just that you can not
use auto_ptr, but a reference counted smart pointer would be
fine and could easily be made thread safe.
Wakeup in the morning and kick the day in the teeth!! Or something like that.
"i don't want to write leak free code or most efficient code, like others traditional (so called expert) coders do."
-
November 12th, 2003, 08:20 AM
#13
a reference counted smart pointer would be
fine and could easily be made thread safe.
Is there any implementation of counted smart pointers in STL ? or in Boost may be ? Let me know I will be very interested in it. If you have your own implementation, I will be interested too.
Thanks.
-
November 12th, 2003, 08:30 AM
#14
Originally posted by pdurye
Is there any implementation of counted smart pointers in STL ? or in Boost may be ? Let me know I will be very interested in it. If you have your own implementation, I will be interested too.
Thanks.
Sure.:)
I think boost has one and here is a quick example of what one
might look like (not a template). This one is thread safe
PHP Code:
volatile class FOO_SMART_PTR
{
public:
explicit FOO_SMART_PTR(FOO* pFOO = 0);
~FOO_SMART_PTR();
FOO_SMART_PTR(const FOO_SMART_PTR& ptr);
FOO_SMART_PTR& operator=(const FOO_SMART_PTR& ptr);
FOO& operator*() const;
FOO* operator->() const;
bool operator!() const;
private:
long* m_RefCount;
FOO* m_pFOO;
void dispose();
};
FOO_SMART_PTR::FOO_SMART_PTR(FOO* pFOO)
:m_pFOO(pFOO), m_RefCount(new long(1))
{
}
FOO_SMART_PTR::FOO_SMART_PTR(const FOO_SMART_PTR& ptr)
:m_pFOO(ptr.m_pFOO), m_RefCount(ptr.m_RefCount)
{
InterlockedIncrement(m_RefCount);
}
FOO_SMART_PTR& FOO_SMART_PTR::operator=(const FOO_SMART_PTR& ptr)
{
if(this != &ptr)
{
dispose();
m_pFOO = ptr.m_pFOO;
m_RefCount = ptr.m_RefCount;
InterlockedIncrement(ptr.m_RefCount);
}
return *this;
}
FOO_SMART_PTR::~FOO_SMART_PTR() throw()
{
dispose();
}
FOO& FOO_SMART_PTR::operator*() const
{
return *m_pFOO;
}
FOO* FOO_SMART_PTR::operator->() const
{
return m_pFOO;
}
bool FOO_SMART_PTR::operator!() const
{
return 0 == m_pFOO;
}
void FOO_SMART_PTR::dispose()
{
if(InterlockedDecrement(m_RefCount) == 0)
{
delete m_RefCount;
delete m_pFOO;
}
}
P.S. I WOULD BE HAPPY IF PEOPLE COULD POINT OUT ANY
PROBLEMS WITH THIS IMPLEMENTATION
Last edited by souldog; November 22nd, 2003 at 10:39 PM.
Wakeup in the morning and kick the day in the teeth!! Or something like that.
"i don't want to write leak free code or most efficient code, like others traditional (so called expert) coders do."
-
November 12th, 2003, 10:00 AM
#15
Code:
FOO_SMART_PTR& FOO_SMART_PTR::operator=(const FOO_SMART_PTR& ptr)
{
if(this != &ptr)
{
dispose();
m_pFOO = ptr.m_pFOO;
*m_RefCount = InterlockedIncrement(ptr.m_RefCount);
}
return *this;
}
Something I do not understand:
Why a dispose here ?
By the way I found the boost reference counted smart pointer: its name is "shared_ptr":
http://www.boost.org/libs/smart_ptr/shared_ptr.htm
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|