473,396 Members | 1,963 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Best way to handle ownership

Hi,

I recently had a problem where I decided to store objects in a vector.
(Previously, I had always stored pointers in vectors). Well, naturally,
when storing an object in a vector, using push_back, the object I had in
hand was getting copied (twice, in fact). That led to a problem, in that my
object contained a "handle" to another object, and when the object being
pushed went out of scope and was destroyed, the referenced object was also
destroyed, making the copy inside the vector refer to a now non-existent
object. Changing my vector to store pointers instead of objects resolved
that problem. But I'm wondering if that's the "best" way to handle the
problem.

I see a few options.

One was to create a copy constructor for my object, which created a new
object and a new sub-object as well. But that had two problems. One, it
meant I was using extra resources and time making that extra sub-object that
I didn't really need. Two, it meant that to get the "handle" that was
stored in the object I pushed into the vector (which I wanted to return from
the function that was doing the push_back), I had to get it by extracting
the object back out of the vector and querying it, which seemed a waste.

Another idea was to make my copy-constructor take ownership of the
handle from the passed object. That meant that the copy constructor had to
change the contents of the object passed to it (to set the handle to NULL),
but... I had declared the parameter as a const reference! I didn't feel
that changing that from a const reference was a great idea (although I could
be wrong...it's just that whenever I make a copy constructor, I always make
the parameter a const reference).

And lastly, I could store pointers in the vector (and write code to
iterate of the vector to destroy the objects when I was done with the list).
That's what I chose to do eventually. But I avoided it at first because I
have no need for polymorphism, so storing pointers wasn't really needed,
except to resolve this ownership issue.

Which of the above methods might be considered "better"? (Or is there
another paradigm for this kind of work with containers? Perhaps using some
kind of reference-counted pointer instead of the bare "handle" inside my
object?)

Thanks,
Howard


Sep 13 '05 #1
14 2699
"Howard" <al*****@hotmail.com> wrote in message
news:uL*******************@bgtnsc04-news.ops.worldnet.att.net...
I recently had a problem where I decided to store objects in a vector.
(Previously, I had always stored pointers in vectors). Well, naturally,
when storing an object in a vector, using push_back, the object I had in
hand was getting copied (twice, in fact). That led to a problem, in that
my object contained a "handle" to another object, and when the object
being pushed went out of scope and was destroyed, the referenced object
was also destroyed, making the copy inside the vector refer to a now
non-existent object.
Did you not observe the rule of three? :) You obviously wrote a destructor,
but did not define the copy constructor or at least declared it privately.
Changing my vector to store pointers instead of objects resolved that
problem. But I'm wondering if that's the "best" way to handle the
problem.
If copying your objects is not viable for any reason, you should disallow
copying. In that case, your only option is to use pointers, which bring
their ownership problems, hence your subject line.

For that reason, the best thing to do would be to store smart pointers in
the vector:

#include <boost/shared_ptr.hpp>

typedef boost::shared_ptr<MyClass> MyClassPtr;

#include <vector>

typedef std::vector<MyClassPtr> MyObjects;
I see a few options.

One was to create a copy constructor for my object, which created a new
object and a new sub-object as well. But that had two problems. One, it
meant I was using extra resources and time making that extra sub-object
that I didn't really need. Two, it meant that to get the "handle" that
was stored in the object I pushed into the vector (which I wanted to
return from the function that was doing the push_back), I had to get it by
extracting the object back out of the vector and querying it, which seemed
a waste.

Another idea was to make my copy-constructor take ownership of the
handle from the passed object.
Not a good idea. That is precisely the reason why std::auto_ptr cannot be
used with standard containers.

Standard containers require that the objects are copy constructible and that
the copies are equivalent.
That meant that the copy constructor had to change the contents of the
object passed to it (to set the handle to NULL), but...
Don't do it :)
I had declared the parameter as a const reference! I didn't feel that
changing that from a const reference was a great idea (although I could be
wrong...it's just that whenever I make a copy constructor, I always make
the parameter a const reference).
Could you use a reference counted pointer (e.g. boost::shared_ptr) for the
handle? That would make the copies of your objects "share the handle"
instead of "own the handle."
And lastly, I could store pointers in the vector (and write code to
iterate of the vector to destroy the objects when I was done with the
list).
Calling delete explicitly makes your code exception-unsafe. Use smart
pointers in the vector.
That's what I chose to do eventually. But I avoided it at first because I
have no need for polymorphism, so storing pointers wasn't really needed,
except to resolve this ownership issue.
Pointers are not only for polymorphism. Dynamic objects allow us extend
object lifetimes: they are not automatic objects, meaning that they don't
get destroyed automatically.
Which of the above methods might be considered "better"? (Or is there
another paradigm for this kind of work with containers? Perhaps using
some kind of reference-counted pointer instead of the bare "handle" inside
my object?)


Either that, or use reference counted pointers in the vector.

Ali
--
Plug: ACCU's Silicon Valley Chapter meets on second Tuesdays. The meetings
are open to public and free of charge. Please come tonight for a talk on
Ada:

http://accu-usa.org/index.html

Sep 13 '05 #2
Howard wrote:
Hi,

I recently had a problem where I decided to store objects in a vector.
(Previously, I had always stored pointers in vectors). Well, naturally,
when storing an object in a vector, using push_back, the object I had in
hand was getting copied (twice, in fact). That led to a problem, in that my
object contained a "handle" to another object, and when the object being
pushed went out of scope and was destroyed, the referenced object was also
destroyed, making the copy inside the vector refer to a now non-existent
object. Changing my vector to store pointers instead of objects resolved
that problem. But I'm wondering if that's the "best" way to handle the
problem.

I see a few options.

One was to create a copy constructor for my object, which created a new
object and a new sub-object as well. But that had two problems. One, it
meant I was using extra resources and time making that extra sub-object that
I didn't really need. Two, it meant that to get the "handle" that was
stored in the object I pushed into the vector (which I wanted to return from
the function that was doing the push_back), I had to get it by extracting
the object back out of the vector and querying it, which seemed a waste.

Another idea was to make my copy-constructor take ownership of the
handle from the passed object. That meant that the copy constructor had to
change the contents of the object passed to it (to set the handle to NULL),
but... I had declared the parameter as a const reference! I didn't feel
that changing that from a const reference was a great idea (although I could
be wrong...it's just that whenever I make a copy constructor, I always make
the parameter a const reference).

And lastly, I could store pointers in the vector (and write code to
iterate of the vector to destroy the objects when I was done with the list).
That's what I chose to do eventually. But I avoided it at first because I
have no need for polymorphism, so storing pointers wasn't really needed,
except to resolve this ownership issue.

Which of the above methods might be considered "better"? (Or is there
another paradigm for this kind of work with containers? Perhaps using some
kind of reference-counted pointer instead of the bare "handle" inside my
object?)

Thanks,
Howard


Hello Howard,
Could you please provide a sample of the code you selected to use?
Regards,
Peter Jansson
Sep 13 '05 #3

"Peter Jansson" <we*******@jansson.net> wrote in message
news:21*********************@newsc.telia.net...
Howard wrote:


Hello Howard,
Could you please provide a sample of the code you selected to use?
Regards,
Peter Jansson


Sure:

HFONT AFonts::FontByNameAndSize( const char* name, short size )
{
HFONT hFont = 0;
bool found = false;
// see if font already created
for (AFontIterator iter = fFonts.begin(); iter != fFonts.end(); ++iter )
{
AFont* pFont = (AFont*)&(*iter);
if ((!strcmp(pFont->fName,name)) &&
(pFont->fSize == size))
{
hFont = pFont->fHFont;
found = true;
}
}
// if not, create it
if (!found)
{
AFont* pFont = new AFont( name, size );
hFont = pFont->fHFont;
fFonts.push_back( pFont );
}
return hFont;
}

previously, that last part was like this:

AFont tempFont( name, size );
hFont = tempFont.fHFont;
fFonts.push_back( tempFont );

(The fHFont is the "handle", a Windows Font resource handle, which I create
in the constructor of an AFont object.)

-Howard
Sep 13 '05 #4
Howard wrote:
Hi,

I recently had a problem where I decided to store objects in a vector.
(Previously, I had always stored pointers in vectors). Well, naturally,
when storing an object in a vector, using push_back, the object I had in
hand was getting copied (twice, in fact). That led to a problem, in that my
object contained a "handle" to another object, and when the object being
pushed went out of scope and was destroyed, the referenced object was also
destroyed, making the copy inside the vector refer to a now non-existent
object. Changing my vector to store pointers instead of objects resolved
that problem. But I'm wondering if that's the "best" way to handle the
problem.
Especially for large objects or those with complicated copy semantics,
storage in a vector by pointer will be far more efficient than storage
by value. The disadvantage of storing pointers though is that the
vector will not manage the lifetimes of the objects referenced. As a
consequence, the client is tasked with the chore of deallocating each
object when its pointer is removed from the vector.
I see a few options.

One was to create a copy constructor for my object, which created a new
object and a new sub-object as well. But that had two problems. One, it
meant I was using extra resources and time making that extra sub-object that
I didn't really need. Two, it meant that to get the "handle" that was
stored in the object I pushed into the vector (which I wanted to return from
the function that was doing the push_back), I had to get it by extracting
the object back out of the vector and querying it, which seemed a waste.
Copying the data along with the object is not only inefficient, it can
also lead to consistency issues. If there is more than one copy of a
data set, which one is "authoritative"? Or is each copy even a copy and
not just its own unique set of data?
Another idea was to make my copy-constructor take ownership of the
handle from the passed object. That meant that the copy constructor had to
change the contents of the object passed to it (to set the handle to NULL),
but... I had declared the parameter as a const reference! I didn't feel
that changing that from a const reference was a great idea (although I could
be wrong...it's just that whenever I make a copy constructor, I always make
the parameter a const reference).
I would call this technique the "hot potato" approach toward resource
ownership. The last object to take possession of the resource is
responsible for freeing it. And while this approach can work, it is
constraining. But as long as the application's copy operations
involving the resource are both limited and not very complicated, it
can be a reasonable choice.
And lastly, I could store pointers in the vector (and write code to
iterate of the vector to destroy the objects when I was done with the list).
That's what I chose to do eventually. But I avoided it at first because I
have no need for polymorphism, so storing pointers wasn't really needed,
except to resolve this ownership issue.
As noted above, storing raw pointers can make for very efficient
vectors, but also require client code to manage the lifetimes of the
referenced objects.
Which of the above methods might be considered "better"? (Or is there
another paradigm for this kind of work with containers? Perhaps using some
kind of reference-counted pointer instead of the bare "handle" inside my
object?) From what I can tell, storing a reference-counted "smart" pointer in the vector would likely be the optimal approach. The smart pointer
would not reference the object's internal data handle (which I gather
is not shared), but rather it would be a used as a pointer to the
object itself.

Storing a smart pointer is nearly as efficient as storing a raw pointer
- but unlike a raw pointer, a smart pointer will automatically manage
the referenced object's lifetime. Because it is an object masquerading
as a pointer, a smart pointer can use its life time to manage the life
time of the referenced object, In short, when a smart pointer is
removed from the vector, the object it points to will automatically be
freed (assuming it has no other outstanding references).

For a smart pointer implementation look either for std::tr1::smart_ptr
or the boost version on which it is based.

Greg

Thanks,
Howard


Sep 13 '05 #5

"Ali Çehreli" <ac******@yahoo.com> wrote in message
news:dg**********@domitilla.aioe.org...
"Howard" <al*****@hotmail.com> wrote in message
news:uL*******************@bgtnsc04-news.ops.worldnet.att.net...
I recently had a problem where I decided to store objects in a vector.
(Previously, I had always stored pointers in vectors). Well, naturally,
when storing an object in a vector, using push_back, the object I had in
hand was getting copied (twice, in fact). That led to a problem, in that
my object contained a "handle" to another object, and when the object
being pushed went out of scope and was destroyed, the referenced object
was also destroyed, making the copy inside the vector refer to a now
non-existent object.
Did you not observe the rule of three? :) You obviously wrote a
destructor, but did not define the copy constructor or at least declared
it privately.


Originally, I had the copy constructor copy the handle, but that led to the
problem of the temporary beign destroyed also destoying the handle I wanted
to keep. So I changed it create a new resource and handle for that
resource.

But that didn't resolve all the issues, because I wanted to return the
internal handle, and the copy made when calling push_back caused my copy
constructor to create a new handle, which was now not the same one I was
returning.

Rather than try to get the actual handle from the object in the vector, (and
because creating a new handle in the first place seemed a waste of
resources), I decided to settle on storing pointers in the vector.

I had this:
{
AFont tempFont( name, size );
// this handle is what I want, but it gets destroyed along with the
temporary
hFont = tempFont.fHFont;
fFonts.push_back( tempFont );
}
...
return hFont;

Now I have this:
{
AFont* pFont = new AFont( name, size );
// now my handle is correct
hFont = pFont->fHFont;
fFonts.push_back( pFont );
}
...
return hFont;
Changing my vector to store pointers instead of objects resolved that
problem. But I'm wondering if that's the "best" way to handle the
problem.


If copying your objects is not viable for any reason, you should disallow
copying. In that case, your only option is to use pointers, which bring
their ownership problems, hence your subject line.

For that reason, the best thing to do would be to store smart pointers in
the vector:

#include <boost/shared_ptr.hpp>


I don't have any of the boost stuff, and so far my boss is resistant to my
using their stuff, since it's not part of the standard C++ libraries. (I'll
work on that, though.)

typedef boost::shared_ptr<MyClass> MyClassPtr;

#include <vector>

typedef std::vector<MyClassPtr> MyObjects;
I see a few options.

One was to create a copy constructor for my object, which created a
new object and a new sub-object as well. But that had two problems.
One, it meant I was using extra resources and time making that extra
sub-object that I didn't really need. Two, it meant that to get the
"handle" that was stored in the object I pushed into the vector (which I
wanted to return from the function that was doing the push_back), I had
to get it by extracting the object back out of the vector and querying
it, which seemed a waste.

Another idea was to make my copy-constructor take ownership of the
handle from the passed object.


Not a good idea. That is precisely the reason why std::auto_ptr cannot be
used with standard containers.

Standard containers require that the objects are copy constructible and
that the copies are equivalent.

Ah, ok.
That meant that the copy constructor had to change the contents of the
object passed to it (to set the handle to NULL), but...


Don't do it :)
I had declared the parameter as a const reference! I didn't feel that
changing that from a const reference was a great idea (although I could
be wrong...it's just that whenever I make a copy constructor, I always
make the parameter a const reference).


Could you use a reference counted pointer (e.g. boost::shared_ptr) for the
handle? That would make the copies of your objects "share the handle"
instead of "own the handle."
And lastly, I could store pointers in the vector (and write code to
iterate of the vector to destroy the objects when I was done with the
list).


Calling delete explicitly makes your code exception-unsafe. Use smart
pointers in the vector.
That's what I chose to do eventually. But I avoided it at first because
I have no need for polymorphism, so storing pointers wasn't really
needed, except to resolve this ownership issue.


Pointers are not only for polymorphism. Dynamic objects allow us extend
object lifetimes: they are not automatic objects, meaning that they don't
get destroyed automatically.


Yeah, I know that, but given the choice between raw pointers and objects, I
chose the object at first, for the same reason: lifetime management.
Which of the above methods might be considered "better"? (Or is there
another paradigm for this kind of work with containers? Perhaps using
some kind of reference-counted pointer instead of the bare "handle"
inside my object?)


Either that, or use reference counted pointers in the vector.


Yep, that would be a good option. One more reason why I'd like to get and
use the boost libraries (and get my boss to use them, too.)

Thanks,
Howard
Sep 13 '05 #6

"Greg" <gr****@pacbell.net> wrote in message

For a smart pointer implementation look either for std::tr1::smart_ptr
or the boost version on which it is based.

Greg


I don't think tr1's available in VC++ 7.0 (Visual Studio 2002), which is
what I'm stuck with for now.

Thanks, though. You're probably right that that's the way to go.

-Howard

Sep 13 '05 #7

"Howard" <al*****@hotmail.com> wrote in message
news:zGFVe.39159$qY1.16195@bgtnsc04-
// see if font already created
for (AFontIterator iter = fFonts.begin(); iter != fFonts.end(); ++iter )
{
AFont* pFont = (AFont*)&(*iter);
if ((!strcmp(pFont->fName,name)) &&
(pFont->fSize == size))
{
hFont = pFont->fHFont;
found = true;
}
}


I just noticed that I should have a "break;" statement there. No sense
continuing the loop once it's found.

I could also drop the boolean and simply return the handle here, but I hate
having multiple return points in a function.

Probably even better would be to put that loop in a find() function of its
own,reducing this function to a simple if/else. Something like this:

return (HFONT hFont = FindFont(name,size)) ? hFont : NewFont(name,size);

where FindFont returns the handle if the font is in the vector (NULL
otherwise), and NewFont creates a new AFont object, pushes it onto the
vector, and returns its handle.

-Howard

Sep 13 '05 #8
"Howard" <al*****@hotmail.com> wrote in message
news:_X******************@bgtnsc04-news.ops.worldnet.att.net...

"Ali ehreli" <ac******@yahoo.com> wrote in message
news:dg**********@domitilla.aioe.org...

#include <boost/shared_ptr.hpp>


I don't have any of the boost stuff, and so far my boss is resistant to my
using their stuff, since it's not part of the standard C++ libraries.
(I'll work on that, though.)


You really should work on convincing your boss to use smart pointers. Use
this snippet to show your boss the resource leaks in your application(s):

void foo()
{
Class * p = new Class(/* ... */);
code_that_may_throw_now_or_in_the_future(/* ... */);

// We may never get here
delete p;
}

Besides, Boost libraries are as best as you can get in any library:
peer-reviewed designs and implementations by C++ experts that are
extensively tested and used. Boost has been recognized as the non-official
extension to the C++ standard for years now. Especially the smart pointers
has been out for years with all the wrinkles ironed out.

In fact, they are so good that some of it is already approved to be part of
the standard. For example, shared_ptr is part of C++ TR1. Here is
an--unfortunately extremely slow--link on what Matt Austern covered in his
talk on TR1 at the last meeting of ACCU's Silicon Valley Chapter:

http://lafstern.org/matt/ACCU_tr1_talk.pdf

[It is still loading for me; his uplink must be very narrow :( Anyway, you
can find lots of information on TR1 on the net.]

What I am trying to say is that, shared_ptr should be considered as being
part of the C++ Standard already.

Ali
--
Plug: ACCU's Silicon Valley Chapter meets on second Tuesdays. The meetings
are open to public and free of charge. Please come tonight for a talk on
Ada:

http://accu-usa.org/index.html

Sep 13 '05 #9

"Ali Çehreli" <ac******@yahoo.com> wrote in message
news:dg**********@domitilla.aioe.org...
"Howard" <al*****@hotmail.com> wrote in message
news:_X******************@bgtnsc04-news.ops.worldnet.att.net...

"Ali ehreli" <ac******@yahoo.com> wrote in message
news:dg**********@domitilla.aioe.org...

#include <boost/shared_ptr.hpp>


I don't have any of the boost stuff, and so far my boss is resistant to
my using their stuff, since it's not part of the standard C++ libraries.
(I'll work on that, though.)


You really should work on convincing your boss to use smart pointers. Use
this snippet to show your boss the resource leaks in your application(s):

void foo()
{
Class * p = new Class(/* ... */);
code_that_may_throw_now_or_in_the_future(/* ... */);

// We may never get here
delete p;
}

Besides, Boost libraries are as best as you can get in any library:
peer-reviewed designs and implementations by C++ experts that are
extensively tested and used. Boost has been recognized as the non-official
extension to the C++ standard for years now. Especially the smart pointers
has been out for years with all the wrinkles ironed out.

In fact, they are so good that some of it is already approved to be part
of the standard. For example, shared_ptr is part of C++ TR1. Here is
an--unfortunately extremely slow--link on what Matt Austern covered in his
talk on TR1 at the last meeting of ACCU's Silicon Valley Chapter:

http://lafstern.org/matt/ACCU_tr1_talk.pdf

[It is still loading for me; his uplink must be very narrow :( Anyway, you
can find lots of information on TR1 on the net.]

What I am trying to say is that, shared_ptr should be considered as being
part of the C++ Standard already.

Ali


Thatnks, Ali. I agree 100%. I think the main reason the boss doesn't want
things not in our current compiler is so we have consistency between
ourselves and any potential contractors or temp programmers he hires.

But I can use all the ammo I can get in the fight! :-)

Thanks again,
Howard
Sep 13 '05 #10
In message <zG*******************@bgtnsc04-news.ops.worldnet.att.net>,
Howard <al*****@hotmail.com> writes

"Peter Jansson" <we*******@jansson.net> wrote in message
news:21*********************@newsc.telia.net...
Howard wrote:

Hello Howard,
Could you please provide a sample of the code you selected to use?
Regards,
Peter Jansson


Sure:

HFONT AFonts::FontByNameAndSize( const char* name, short size )
{
HFONT hFont = 0;
bool found = false;
// see if font already created
for (AFontIterator iter = fFonts.begin(); iter != fFonts.end(); ++iter )
{
AFont* pFont = (AFont*)&(*iter);


Unless your AFontIterator has very strange semantics, there's no need
for this. There's nothing (non-evil!) you'd want to do with the pointer
that the iterator can't do equally well, and having unnecessary
non-owning copies of pointers lying around is inviting trouble later on.
if ((!strcmp(pFont->fName,name)) && if ((!strcmp(iter->fName,name)) && (pFont->fSize == size)) (iter->fSize == size)) {
hFont = pFont->fHFont; hFont = iter->fHFont; found = true;
}
}
// if not, create it
if (!found)
{
AFont* pFont = new AFont( name, size );
hFont = pFont->fHFont;
fFonts.push_back( pFont );
}
return hFont;
}

previously, that last part was like this:

AFont tempFont( name, size );
hFont = tempFont.fHFont;
fFonts.push_back( tempFont );

(The fHFont is the "handle", a Windows Font resource handle, which I create
in the constructor of an AFont object.)


--
Richard Herring
Sep 14 '05 #11

"Richard Herring" <ju**@[127.0.0.1]> wrote in message
news:tH**************@baesystems.com...
In message <zG*******************@bgtnsc04-news.ops.worldnet.att.net>,
Howard <al*****@hotmail.com> writes

"Peter Jansson" <we*******@jansson.net> wrote in message
news:21*********************@newsc.telia.net.. .
Howard wrote:
Hello Howard,
Could you please provide a sample of the code you selected to use?
Regards,
Peter Jansson


Sure:

HFONT AFonts::FontByNameAndSize( const char* name, short size )
{
HFONT hFont = 0;
bool found = false;
// see if font already created
for (AFontIterator iter = fFonts.begin(); iter != fFonts.end(); ++iter )
{
AFont* pFont = (AFont*)&(*iter);


Unless your AFontIterator has very strange semantics, there's no need
for this. There's nothing (non-evil!) you'd want to do with the pointer
that the iterator can't do equally well, and having unnecessary
non-owning copies of pointers lying around is inviting trouble later on.
if ((!strcmp(pFont->fName,name)) &&

if ((!strcmp(iter->fName,name)) &&
(pFont->fSize == size))

(iter->fSize == size))
{
hFont = pFont->fHFont;

hFont = iter->fHFont;
found = true;


I had thought that it wasn't proper to use the iterator as if it were a
pointer, and had seen example code like this somewhere. If I can use the
iterator directly, as if it were actually an object pointer, then that's
great.

Thanks,
Howard

Sep 14 '05 #12
In message <Wt*********************@bgtnsc05-news.ops.worldnet.att.net>,
Howard <al*****@hotmail.com> writes

"Richard Herring" <ju**@[127.0.0.1]> wrote in message
news:tH**************@baesystems.com...
In message <zG*******************@bgtnsc04-news.ops.worldnet.att.net>,
Howard <al*****@hotmail.com> writes

"Peter Jansson" <we*******@jansson.net> wrote in message
news:21*********************@newsc.telia.net. ..
Howard wrote:
>

Hello Howard,
Could you please provide a sample of the code you selected to use?
Regards,
Peter Jansson

Sure:

HFONT AFonts::FontByNameAndSize( const char* name, short size )
{
HFONT hFont = 0;
bool found = false;
// see if font already created
for (AFontIterator iter = fFonts.begin(); iter != fFonts.end(); ++iter )
{
AFont* pFont = (AFont*)&(*iter);
Unless your AFontIterator has very strange semantics, there's no need
for this. There's nothing (non-evil!) you'd want to do with the pointer
that the iterator can't do equally well, and having unnecessary
non-owning copies of pointers lying around is inviting trouble later on.
if ((!strcmp(pFont->fName,name)) &&

if ((!strcmp(iter->fName,name)) &&
(pFont->fSize == size))

(iter->fSize == size))
{
hFont = pFont->fHFont;

hFont = iter->fHFont;
found = true;


I had thought that it wasn't proper to use the iterator as if it were a
pointer, and had seen example code like this somewhere.


What's improper is to assume that there is an implicit conversion
between iterator and pointer. Some implementations of std::vector<T> may
typedef T* as their iterator type, but you can't rely on this.
If I can use the
iterator directly, as if it were actually an object pointer, then that's
great.

You can't assume that an iterator *is* a pointer, but its pointer-*like*
behaviour (via operator*() and operator->() ) is guaranteed by the
standard at 24.1.

--
Richard Herring
Sep 15 '05 #13

"Richard Herring" <ju**@[127.0.0.1]> wrote in message
If I can use the
iterator directly, as if it were actually an object pointer, then that's
great.

You can't assume that an iterator *is* a pointer, but its pointer-*like*
behaviour (via operator*() and operator->() ) is guaranteed by the
standard at 24.1.


Excellent. Thanks...
-Howard
Sep 15 '05 #14
> I recently had a problem where I decided to store objects in a vector.
(Previously, I had always stored pointers in vectors). Well, naturally,
when storing an object in a vector, using push_back, the object I had in
hand was getting copied (twice, in fact). That led to a problem, in that my
object contained a "handle" to another object, and when the object being
pushed went out of scope and was destroyed, the referenced object was also
destroyed, making the copy inside the vector refer to a now non-existent
object. Changing my vector to store pointers instead of objects resolved
that problem. But I'm wondering if that's the "best" way to handle the
problem.


Actually, this for me was the reason to avoid STL and try to develop
better variant. My solution goes like this:

Array<BigFoo> bigfoos;

BigFoo& n = bigfoos.Add();

// do whatever with newly created BigFoo.

Of course, this requires some shift in metodology - you have to provide
default constructor (but default constructor tend to be cheap) and
methods to setup object instead of using fat constructors, but overall I
believe that this is the "best" way how to handle this problem, of
course, as long as "best" is allowed to avoid "standard".

(see http://upp.sourceforge.net/srcdoc$NTL$en-us.html)

BTW, you can achieve the somewhat similar behaviour with STL as well

vector<BigFoo> bigfoos;
bigfoos.push_back(BigFoo());
BigFoo& n = bigfoos.back();

but it little but less effective and Array works even when BigFoo has no
copy constructor at all...

Mirek
Sep 18 '05 #15

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Ryan | last post by:
We have a DTS package developed on our development PC's (SQL 7). It runs fine. When we schedule it on the server (SQL 7), it fails. We have been able to find that this is a known issue down to the...
16
by: D Witherspoon | last post by:
I am developing a Windows Forms application in VB.NET that will use .NET remoting to access the data tier classes. A very simple way I have come up with is by creating typed (.xsd) datasets. For...
4
by: tarmat | last post by:
I've been using code such as the following, whereby I call the constructor of a class with an object allocated on the heap. The class is responsible for tidying up the memory. class Base{};...
11
by: Jacob | last post by:
I am trying to find the best way of documenting (in code and comments) ownership of secondary contained objects. This is my current status, and I would appreciate feedback on it: Case 1: ...
2
by: Benden Ziyade | last post by:
Hello; I want to write a C program that check file ownership in /bin directory(ls, mkdir...). But I don't know how I start. I'm happy with your helping.
9
by: Andrew | last post by:
Apologies for the double-post.. I'm new, just getting used to this.. and should have posted this way in the first place.. How does one go about taking ownership of a registry key using C# & .NET...
1
by: ShaiH | last post by:
When I create a file from a simple command line application written in C# the file ownership given to the newly created file is of administrators group although I am running this application in my...
17
by: Gabriel Zachmann | last post by:
Is it correct to say that the typical ownership problem, which frequently arises in C++, does not occur normally in Python? Best regards, Gabriel. --...
0
by: digz | last post by:
In the code below , a simplified version I need to pass a smart pointer to function f which I control .I cannot use std::auto_ptr as a parameter to f because it releases ownership on copy...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.