From: Jim Langston on
I have a seperate thread function that I was passing a class pointer through
a void pointer.

Then I realized that the location of my object was changing because it was
in a vector like this:

std::vector< ThreadConnection > Connections;
std::vector< ThreadConnection >::iterator it = Connections.insert(
Connections.end(), ThreadConnection() );

And being passed like this:

(*it).Handle = reinterpret_cast<HANDLE>( _beginthreadex(0, 0,
ClientConnection, static_cast<void*>( &*it ), 0, &(*it).ThreadID) );

The static_cast<void*>( &*it ) is where it's being passed. All well and
good, and it works, until another ThreadConnection is inserted into the
vector, then the pointer is invalid (took me a little while to figure this
one out).

So it seems the best solution would be to either pass the pure iterator,
which I understand is always supposed to point to the same object, or a
reference. But how to do this through a void pointer? The only thing I can
think of is something like this:

struct ThreadConnWrapper
{
ThreadConnection& ThreadConnRef;
ThreadConnWrapper( ThreadConnection& Ref ): ThreadConnRef( Ref );
};

then creating an instance with:
ThreadConnWrapper PassRef( *it1 );

I try this, and after I add a new object to the vector, the reference is
invalid.

So I try with an iterator (change the above to a std::vector<
ThreadConnection >::iterator ) and .. it's invalid as soon as anything is
pushed to the vector.

So, what can I do other than changing my vector to:
std::vector< ThreadConnection* > Connections;
then using new and passing the pointer that won't change?



From: James Dennett on
Jim Langston wrote:
> I have a seperate thread function that I was passing a class pointer through
> a void pointer.
>
> Then I realized that the location of my object was changing because it was
> in a vector like this:
>
> std::vector< ThreadConnection > Connections;
> std::vector< ThreadConnection >::iterator it = Connections.insert(
> Connections.end(), ThreadConnection() );
>
> And being passed like this:
>
> (*it).Handle = reinterpret_cast<HANDLE>( _beginthreadex(0, 0,
> ClientConnection, static_cast<void*>( &*it ), 0, &(*it).ThreadID) );
>
> The static_cast<void*>( &*it ) is where it's being passed. All well and
> good, and it works, until another ThreadConnection is inserted into the
> vector, then the pointer is invalid (took me a little while to figure this
> one out).
>
> So it seems the best solution would be to either pass the pure iterator,
> which I understand is always supposed to point to the same object

That understanding is incorrect; when the item is moved,
iterators to it are also invalidated.

>, or a
> reference.

References are also invalidated at the same time as pointers.

> But how to do this through a void pointer? The only thing I can
> think of is something like this:
>
> struct ThreadConnWrapper
> {
> ThreadConnection& ThreadConnRef;
> ThreadConnWrapper( ThreadConnection& Ref ): ThreadConnRef( Ref );
> };
>
> then creating an instance with:
> ThreadConnWrapper PassRef( *it1 );
>
> I try this, and after I add a new object to the vector, the reference is
> invalid.

Yes, that doesn't address the issue at all.

> So I try with an iterator (change the above to a std::vector<
> ThreadConnection >::iterator ) and .. it's invalid as soon as anything is
> pushed to the vector.
>
> So, what can I do other than changing my vector to:
> std::vector< ThreadConnection* > Connections;
> then using new and passing the pointer that won't change?

You can use a std::list, which doesn't move items, or you
can use a std::vector< boost::shared_ptr< ThreadConnection > >
if you have access to boost (or std::tr1), or you can pass
the items index inside the vector if that's not going to
change. std::list is often useful in situations like this
precisely because iterators to items tend to be guaranteed
to remain valid.

-- James
From: Josh Sebastian on
James Dennett wrote:
> Jim Langston wrote:
> > I have a seperate thread function that I was passing a class pointer through
> > a void pointer.
> >
> > Then I realized that the location of my object was changing because it was
> > in a vector like this:
> >
> > std::vector< ThreadConnection > Connections;
> > std::vector< ThreadConnection >::iterator it = Connections.insert(
> > Connections.end(), ThreadConnection() );
> >
> > And being passed like this:
> >
> > (*it).Handle = reinterpret_cast<HANDLE>( _beginthreadex(0, 0,
> > ClientConnection, static_cast<void*>( &*it ), 0, &(*it).ThreadID) );
> >
> > The static_cast<void*>( &*it ) is where it's being passed. All well and
> > good, and it works, until another ThreadConnection is inserted into the
> > vector, then the pointer is invalid (took me a little while to figure this
> > one out).
>
> You can use a std::list, which doesn't move items

That was my first thought, too.

> or you can pass
> the items index inside the vector if that's not going to
> change.

Just to add some meat to that:

template<typename T>
class vector_elm_ref {
public:
vector_elm_ref(std::vector<T>& vec, std::vector<T>::size_type idx)
: vec_(vec), idx_(idx) { }
T& operator*() { return vec[idx]; }

private:
std::vector<T>& vec;
std::vector<T>::size_type idx;
};

> > std::vector< ThreadConnection > Connections;
> > std::vector< ThreadConnection >::iterator it = Connections.insert(
> > Connections.end(), ThreadConnection() );

vector_elm_ref<ThreadConnection>* ptc_ref = new
vector_elm_ref<ThreadConnection>(Connections, it -
connections.begin());

(**ptc_ref).Handle = reinterpret_cast<HANDLE>( _beginthreadex( 0, 0,
ClientConnection, ptc_ref, 0, &((**ptc_ref).ThreadID) ) );

Josh

From: Jim Langston on

"James Dennett" <jdennett(a)cox.net> wrote in message
news:JcAKf.34$p43.0(a)fed1read05...
> Jim Langston wrote:
>> I have a seperate thread function that I was passing a class pointer
>> through a void pointer.
>>
>> Then I realized that the location of my object was changing because it
>> was in a vector like this:
>>
>> std::vector< ThreadConnection > Connections;
>> std::vector< ThreadConnection >::iterator it = Connections.insert(
>> Connections.end(), ThreadConnection() );
>>
>> And being passed like this:
>>
>> (*it).Handle = reinterpret_cast<HANDLE>( _beginthreadex(0, 0,
>> ClientConnection, static_cast<void*>( &*it ), 0, &(*it).ThreadID) );
>>
>> The static_cast<void*>( &*it ) is where it's being passed. All well and
>> good, and it works, until another ThreadConnection is inserted into the
>> vector, then the pointer is invalid (took me a little while to figure
>> this one out).
>>
>> So it seems the best solution would be to either pass the pure iterator,
>> which I understand is always supposed to point to the same object
>
> That understanding is incorrect; when the item is moved,
> iterators to it are also invalidated.
>
>>, or a reference.
>
> References are also invalidated at the same time as pointers.
>
>> But how to do this through a void pointer? The only thing I can think of
>> is something like this:
>>
>> struct ThreadConnWrapper
>> {
>> ThreadConnection& ThreadConnRef;
>> ThreadConnWrapper( ThreadConnection& Ref ): ThreadConnRef( Ref );
>> };
>>
>> then creating an instance with:
>> ThreadConnWrapper PassRef( *it1 );
>>
>> I try this, and after I add a new object to the vector, the reference is
>> invalid.
>
> Yes, that doesn't address the issue at all.
>
>> So I try with an iterator (change the above to a std::vector<
>> ThreadConnection >::iterator ) and .. it's invalid as soon as anything is
>> pushed to the vector.
>>
>> So, what can I do other than changing my vector to:
>> std::vector< ThreadConnection* > Connections;
>> then using new and passing the pointer that won't change?
>
> You can use a std::list, which doesn't move items, or you
> can use a std::vector< boost::shared_ptr< ThreadConnection > >
> if you have access to boost (or std::tr1), or you can pass
> the items index inside the vector if that's not going to
> change. std::list is often useful in situations like this
> precisely because iterators to items tend to be guaranteed
> to remain valid.

Thanks, changed it to std::list and wound up not having to change any code
at all. Passing iterator to the object in the list and all is well.