Jason on Tue, 16 Jul 2002 09:57:12 -0400


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: [PLUG] [ON TOPIC] passing a pointer to an object to an object (c++)


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Monday 15 July 2002 16H:14, Fred K Ollinger wrote:
> > On Monday 15 July 2002 08:24 am, Walt Mankowski wrote:
> > > That code segfaults?  I'm surprised it even compiles.  What type is
> > > qlBillBoard?  It looks like it must be QLabel.  Then you either want
> > > to say
> >
> > it compiles perfectly but causes a memory leak.
> >
> > what you really want is a:
> > qlBillBoard(qlIncoming);
> > instead.  But make sure you are not deleteing your qlIncoming somewhere.
> > Remember QWidgets are all QObjects and can be deleted if the parent goes
> > away.
>
> Since this is a short live installer, I'm not that worried about memory
> leaks, but I would rather do w/o them.
>
> > Your segfault is 90% sure in the fact that a new on QLabel calls show,
> > well the QLabel gets pissed because your parent pointer is 0.
>
> Got it.
>
> > Please read the Qt docs and this will become very clear, otherwise I have
> > done some Qt training, so you can fire off questions to me directly.
>
> I wouldn't waste plug's time if I hadn't read the docs several times.
>
> I have a QLabel *qlBillBoard, which is part of my installer wizard. I
> would like to point to this in an object called voxInstallCommon, which is
> called when one clicks 'finish' in the wizard.
>
> I am able to pass the pointer to the qlBillBoard and it works great for a
> single function. However, when I try to send it over in the constructor,
> all hell breaks loose.
>
> I'm going to try Jason's syntax, and see what happens.
Ian's more familiar with what goes on in the QT library, so make sure you 
follow his advice (as well).

>
> voxWizardInstall creates a voxInstallCommon:
>
> voxInstallCommon myinstall(*qlBillBoard);
>
> now I want to take that pointer and point to the same memory area in the
> constructor for the voxInstallCommon.

This is probably OK, but you probably want to make sure that the 
voxInstallCommon object releases it's pointer and that voxInstallCommon is 
cleaned up before the object is deleted in voxWizardInstall.

>
> Sorry this wasn't more clear. Will this always create the memory leak?
>
> How to avoid this? Can't I just destroy the pointer in voxInstallCommon
> before voxInstallCommon is destroyed?

Probably not. If the object was created in voxWizardInstall, doesn't it also 
get deleted there? You don't want to delete it more than once. You may just 
want to set your pointer to NULL in the destructor of voxInstallCommon.

And, as Ian mentioned, QObjects can be deleted if their parent is freed up. 
So, you need to understand when this is likely to occur. Ian is definitely 
the best person to help you understand that.

In general, you usually want to instantiate and delete objects in the same 
place. You can pass references (or pointers) around, but you shouldn't delete 
the object that you've passed. If you do, the original reference (pointer) 
will no longer be valid (but may appear valid).

If you really want to delete a reference (pointer) to an object (or expect 
this to happen, i.e. in a module that you pass the object to), then you 
probably need to make a local copy or clone of the object. Then, you can 
delete the local copy and the original object is still valid.

There are rare situations where you want to *pass an object on* to another 
object. This should probably be some sort of design pattern (probably already 
is). In this instance, you would want the initial *owner* of the object to 
release its pointer (usually just set the pointer to NULL) after passing it 
along, so that it will no longer reference the object. But, this is 
definitely the exception rather than the rule.

The "rule" would be:
Only allocate and delete each object once and do it in as near the same place 
(object) as possible.

Also, try not to keep too many pointers to other objects arround (ala setting 
in the constructor). It is natural to want to decrease parameter passing, but 
don't let it get out of hand. For example, you don't want every object having 
a pointer to every other object. You probably don't want to pass every 
parameter an object needs to every function either. You probably want to be 
somewhere in the middle. Data that every member function needs almost 
certainly wants to be member variables for that class.

Think of the interface to each class as a contract. You don't want every class 
to have a contract with *all* of the other classes. This is just a general 
recommendation.

There are cases where it is wise to set a pointer in a constuctor, such as 
when the pointer is needed by the majority of functions in the object, for 
the lifetime of the object. Your case may very well be one of these 
situations. Just something to think about.

Suggestions when dealing with pointers:
1) Don't. Try to use references instead when possible.
2) Initialize pointers to a known value (NULL or 0), or even better, a 
NullObject - but I won't get into that right now. Note: if you instantiate 
the object when you declare the pointer variable, then you have initialized 
it.
3) Set pointers back to a known value (NULL or NullObject) after you delete 
them.
4) Check if a pointer is valid before dereferencing it. At a minimum, use an 
Assert.

Some runtime libraries will do some of these steps for you. In particular, 
your pointers are probably already initialized to 0. But, it's still good 
practice (particularly for portability) to double check that. Not making sure 
that *all* invalid pointers are set to NULL or 0 makes the check in part 4 
pretty useless.

>
> I think that since passing the pointer for each function works flawlessly,
> I'll do that for all the functions. This is going to have another arg to a
> ton of functions, but it will work properly. Is there a downside to this
> besides more typing?

Generally speaking, you probably want to look for objects that have much of 
the data that you need to pass, then pass a reference to that object. The 
function would then just use accessor functions to get the data from the 
object reference.

>
> Thanks for all the help on this. Before you all started helping me I
> didn't know quite how confused I was. Hopefully a few more rereads of
> these emails will straighten this out.

Trying not to bombard you with too much info too quickly. A lot of this is why 
pointers are to be used with much care. Again, references are nice (won't 
solve all of these potential problems for you, but you definitely start with 
fewer worries).

>
> Good day,
>
> Fred
>
>
HTH,
Jason Nocks
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iEYEARECAAYFAj00JgsACgkQ3CryLfCgqRmG8ACeId8KOrx398hGF2VRkG5mUqCI
5xQAn2DKyIEmOOs8yDIUClt1cW1CZkdS
=V/6k
-----END PGP SIGNATURE-----


______________________________________________________________________
Philadelphia Linux Users Group       -      http://www.phillylinux.org
Announcements-http://lists.phillylinux.org/mail/listinfo/plug-announce
General Discussion  -  http://lists.phillylinux.org/mail/listinfo/plug