[openbeos] Re: Pointer or reference?

  • From: "Scott MacMaster" <scott@xxxxxxxxxxxxxxxxxx>
  • To: <openbeos@xxxxxxxxxxxxx>
  • Date: Thu, 1 Apr 2004 01:41:18 -0500

> In situations where a child object is added to a parent, the assumption
> is that the parent takes ownership of the child object, and thus should
> be responsible for deleting it. When you remove an object from the
> hierarchy, you are reclaiming ownership of it as well as the
> responsibility for deleting it. Since it has been removed from the
> hierarchy, the parent should no longer have a pointer to it and can not
> delete the removed child.

Right, the owner should take care of deleting it's children.  If an object
deletes itself then that applies that the object is the owner of itself.  In
c++ programs this is never.  Thus an object in c++ should never delete
itself.


> > I'm not familiar with these other API's, however I still say it's a
> > bad
> > thing.  For one thing it forces you C++ differently then it was
> > intended.
> > Objects you explicitly allocate memory for should be explicitly
> > deallocated.
> > The biggest issue this introduces, is that you can't trust any
> > pointer to
> > the object.
>
> Pointers to child objects should be entirely trustworthy until the
> parent is deleted, which is normally pretty evident. Objects don't just
> randomly delete themselves, or delete themselves at 4pm on a Wednesday,
> you have to do something to lead up to it. When you do something that
> will cause an object to be deleted you can assume its owned children
> will be deleted.

The problem isn't entirely pointers to child objects.  Other objects can
obtain pointers to the object.  Which can lead to objects being randomly
deleted (at least it would appear random to the parent).  Well, I suppose
this isn't a big issue you'd almost have to be written bad code on purpose.


> > You would have to manually destroy objects you created dynamically.
> > Which,
> > of course could be done by using FindView() or a stored pointer.
> > For, the
> > few cases where it would be more convenient to create a object
> > dynamically
> > it would also be more convenient to store the pointer rather then
> > repeated
> > use if FindView().  For the majority of the time your could just
> > create
> > objects on the stack and they will be implicitly destroyed when the
> > parent
> > is destroyed.
>
> The stack isn't the answer, especially in Be. From my viewpoint the
> reason why the BeAPI uses so many pointers is not an ownership issue,
> but rather a multithreading issue.

That seems unlikely.

> This is also why creating objects on
> the stack is incorrect. An automatic (stack) variable can only be
> accessed from the thread that created it.

That's definitely wrong.  I'm certain I've accessed the stack from a
seperate thread.  In any case, I decided to run a test program.  I
initialized a int to 10 in one thread, later I displayed and changed the
value in another thread, the back in the first thread I displayed the value
again.  Everything worked perfectly and as expected.


> Since a BApplication's
> message loop is run from the main program thread, and each BWindow's
> message loop run in its own thread, you have to allocate memory that
> they both need to access on the heap. Memory allocated on the heap is
> most conveniently accessed with pointers. Also, in a multithreaded
> environment, stack space needs to be used more conservatively since the
> stack is split up between threads, with the stack size limited by the
> difference between the starting address of one thread's stack and the
> starting address of the next thread. On BeOS "the stack size is fixed
> at around 256k." A real easy way to crash your program would be to
> create a 256k object on the stack.

I find that hard to believe.  Espacially such a small limit.  In any case, I
decided to test it.

long double largeStackObject[600000];
largeStackObject[599999] = 9;

No crashes.  The program worked fine.


> On the topic of references vs. pointers, references are a good way of
> implying that "this data should only be accessed from this thread!"

Odd, I've never heard this before.  Personally, I avoid having a thread
directly access data that belongs to another thread.  In any case, thread
coding conventions is another topic.

> Say for instance that MessageReceived() took a reference to a BMessage
> created on the stack as opposed to a pointer to a message on the heap.
> Now say that you want to have a few slave threads do something with the
> data in the message, and have them signal you when they are finished
> accessing its data, at which point you return from MessageReceived().
> With a reference to a message on the stack you would have to make a
> copy of the message (or the relevent data) on the heap and use that.

You'd have to do that in either case.  When MessageReceived() returns the
message is removed from the queue and deleted.  So in either case you have
copy the data for each thread.


> Another annoying effect of this would be to limit messages to less than
> 256k in size, a limit that would change depending on stack usage. While
> this scenario of controlling slave threads from MessageReceived() isn't
> very likely, and isn't necessarily a good idea, I hope it illustrates
> some of the issues of retreating to the stack.

With the above evidence that the limt isn't 256k along with your inaccurate
MessageReceived() example this doesn't illustrate anything.  However, if you
are working with a lot of data, I would recommend you put a pointer to the
BMessage instead of putting the data in the BMessage.  Otherwise, you're
fill up the threads port pretty quickly.  Also, a lot of copying during the
sending process can be avoided.


> To summarize, heap == thread friendly, stack == thread's worst
> nightmare.

You should make sure you stack objects lifetime is longer then that of the
thread.  Otherwise, there's no issue that makes accessing the heap or the
stack a nightmare.  What is a nightmare with threads are mismanagement of
your data and a poorly designed data access structure across your threads.


> > The only time where automatic deletion of any kind is ok is in
> > garbage
> > collection.
>
> Automatic deletion is perfectly fine if it is documented, and it is the
> about the only correct way to handle deleting ownership hierarchies. It
> is also a good example of the DRY (Don't Repeat Yourself) principle. If
> a parent didn't delete its children, every application using that API
> would have similar code to walk the hierarchy and delete the children,
> a massive repetition of code.

If it documented, it isn't as bad.  However, it's about the worst way to
handle deleting ownership hierarchies.  A parent should delete it's children
and it's children should delete there children, etc.


Later,
Scott MacMaster


Other related posts: