LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-27-2011, 03:58 PM   #1
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Rep: Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723
Question [C++] Reference counting, jumps, and exceptions


I am writing a simple programming language interpreter, and it makes very heavy use of reference counting to track resoruces. I have a class called RefcountObject that has a reference count field and two methods: getref() (which adds to the count) and putref() (which subtracts from the count). putref() also checks of the count reached zero. If so, it deletes itself.

I would like to implement exceptions in the interpreted language, and that should be simple to do with either longjmp() or C++'s exception handling system. The problem is that if you jump from one point in the code to another, you abandon all these pointers without calling putref() on them.

Is there any good solution?
 
Old 04-27-2011, 04:22 PM   #2
SigTerm
Member
 
Registered: Dec 2009
Distribution: Slackware 12.2
Posts: 379

Rep: Reputation: 234Reputation: 234Reputation: 234
Quote:
Originally Posted by MTK358 View Post
I am writing a simple programming language interpreter, and it makes very heavy use of reference counting to track resoruces. I have a class called RefcountObject that has a reference count field and two methods: getref() (which adds to the count) and putref() (which subtracts from the count). putref() also checks of the count reached zero. If so, it deletes itself.
I'd advise to rename methods got something like addRef/decRef, because get/put does not represent what function does. "put" is normally used to assign value to an internal field, not increase it, and "get" is used to get a value without changing it.

Quote:
Originally Posted by MTK358 View Post
I would like to implement exceptions in the interpreted language, and that should be simple to do with either longjmp() or C++'s exception handling system. The problem is that if you jump from one point in the code to another, you abandon all these pointers without calling putref() on them.

Is there any good solution?
The solution is not to use "jumps".
(A C++ approach) When exception is thrown, call destructor for all local variables, then repeat the same process within the caller, then within caller's caller, etc. Keep doing that until you reach top level of execution, or until exception is handled. For unhandled exceptions terminate the program.
Instead of using a "pointer a RefCounter", use a "smart pointer to RefCounter" which calls refcounter's "decRef" method when the pointer is destroyed. This way RefCounter will be deleted even if exception has been thrown.
Since it is your language, then you don't have to introduce classes and destructors. Make a special refcounting pointer type that calls addRef/decRef when necessarry (addRef when assigned a new value, decRef, when it goes out of scope or gets destroyed).

Or you could try to implement garbage collector.

Last edited by SigTerm; 04-27-2011 at 04:23 PM.
 
Old 04-27-2011, 04:50 PM   #3
jcmlq
Member
 
Registered: Aug 2009
Posts: 32

Rep: Reputation: 19
Don't use setjmp/longjmp, it's really nothing more than a goto that can keep track of where you came from.

Try/Catch allows you to pass around context and *unwinds* the stack all the way back to the open of the try block. That means that each local variable in each scope will have it's destructor called.

I'd suggest you use auto_ptr for the do it yourself approach, or shared_ptr if using boost is an option.
 
1 members found this post helpful.
Old 04-27-2011, 05:28 PM   #4
David1357
Senior Member
 
Registered: Aug 2007
Location: South Carolina, U.S.A.
Distribution: Ubuntu, Fedora Core, Red Hat, SUSE, Gentoo, DSL, coLinux, uClinux
Posts: 1,302
Blog Entries: 1

Rep: Reputation: 107Reputation: 107
Quote:
Originally Posted by jcmlq View Post
...shared_ptr if using boost is an option.
You can use std::tr1::shared_ptr if you have a new enough g++:
Code:
[user@machine:~]:g++ --version
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

[user@machine:~]:find /usr/include -name '*shared_ptr*'
/usr/include/c++/4.4/tr1/shared_ptr.h
/usr/include/c++/4.4/bits/shared_ptr.h
 
Old 04-27-2011, 07:18 PM   #5
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443

Original Poster
Blog Entries: 3

Rep: Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723
Quote:
Originally Posted by SigTerm View Post
I'd advise to rename methods got something like addRef/decRef, because get/put does not represent what function does. "put" is normally used to assign value to an internal field, not increase it, and "get" is used to get a value without changing it.
I thought that another member (I think it was "Nominal Animal") said that the proper terms are "get" and "put". That's why I named them that way.


Quote:
(A C++ approach) When exception is thrown, call destructor for all local variables, then repeat the same process within the caller, then within caller's caller, etc. Keep doing that until you reach top level of execution, or until exception is handled. For unhandled exceptions terminate the program.
That might work, but it seems kind of tedious to have try/catch blocks around every call to a child node.

Code:
Instead of using a "pointer a RefCounter", use a "smart pointer to RefCounter" which calls refcounter's "decRef" method when the pointer is destroyed. This way RefCounter will be deleted even if exception has been thrown.
Maybe, but will it decrease performance?

Quote:
Since it is your language, then you don't have to introduce classes and destructors.
I don't get that part. There will be no memory management in the interpreted program, the C++ interpreter takes care of that. And the interpreted language doesn't have classes.

Last edited by MTK358; 04-27-2011 at 07:19 PM.
 
Old 04-27-2011, 09:32 PM   #6
SigTerm
Member
 
Registered: Dec 2009
Distribution: Slackware 12.2
Posts: 379

Rep: Reputation: 234Reputation: 234Reputation: 234
Quote:
Originally Posted by MTK358 View Post
I thought that another member (I think it was "Nominal Animal") said that the proper terms are "get" and "put". That's why I named them that way.
Typically "get" is a const method returns value without changing it, and "put"|"set" assigns new value. It is matter of taste, though. See Qt 4 documentation for examples.

Quote:
Originally Posted by MTK358 View Post
That might work, but it seems kind of tedious to have try/catch blocks around every call to a child node.
Exception is a "severe" situation, so I'd try to insert one "try/catch" block at the top level, instead of putting them around every call.

Quote:
Originally Posted by MTK358 View Post
I don't get that part. There will be no memory management in the interpreted program, the C++ interpreter takes care of that. And the interpreted language doesn't have classes.
I thought you were talking about implementing exception mechanism in interpreted language you're developing. It looks like I was mistaken.

If you have a C++ RefCounter class, and want to release it even in case of C++ exception, then you'll need to use modified smart pointer class and forget about jumps. I'd recommend to look at QSharedPointer for example. If you don't NEED to know number of references, I'd recommend to try to replace it with any smart pointer class (boost::shared_ptr, for example). There are multiple ways to approach the problem.

Quote:
Originally Posted by MTK358 View Post
Maybe, but will it decrease performance?
Instead of trying to guess the performance, you need to measure it with profiler. Linux has gprof for that.
I'd advise to keep code readable and deal with performance problems only when you run into them. From my experience, the slowest operations are memory allocation/deallocation (new/delete). Reference counter will add few assembly instructions, but it'll save a lot of coding time.
 
Old 04-28-2011, 08:44 AM   #7
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443

Original Poster
Blog Entries: 3

Rep: Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723
Quote:
Originally Posted by SigTerm View Post
I thought you were talking about implementing exception mechanism in interpreted language you're developing. It looks like I was mistaken.
Acually, implementing exceptions in the interpreted language is the entire reason for this thread, by adding Throw and Catch AST nodes. I got very confused by this sentence you wrote, and I still don't understand what you meant by it:

Quote:
Since it is your language, then you don't have to introduce classes and destructors.
The way I interpreted it, I tought it meant that the interpreted language had classes and that I shouldn't need to add the concepts or constructors and destructors to the interpreted language. But the interpreted language doesn't have the concept of classes in the first place!

If that's not what you meant, could you explain what you meant there?

Last edited by MTK358; 04-28-2011 at 08:48 AM.
 
Old 04-28-2011, 10:10 AM   #8
SigTerm
Member
 
Registered: Dec 2009
Distribution: Slackware 12.2
Posts: 379

Rep: Reputation: 234Reputation: 234Reputation: 234
Quote:
Originally Posted by MTK358 View Post
If that's not what you meant, could you explain what you meant there?
I meant to say that when exception is thrown within your language, walk through every local variable and call a cleanup procedure, repeat same process in caller, and keep doing that until exception is handled.

A cleanup procedure for variable is technically a destructor, which is hidden within interpreter's implementation and is completely invisible from within the program being executed by interpreter.
Language itself may not have a concept of "destructors" or "classes".
In other words, if every int variable within interpreter calls "decRef" when it goes out of scope, this functionality is a destructor. However, a program being interpreted will not know about existence of such destructor.
 
Old 04-30-2011, 12:46 PM   #9
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443

Original Poster
Blog Entries: 3

Rep: Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723
I'm starting to think that putting try/catch around everything is not a very good idea, because I'll need so much of them (and I haven't thoguht of the parser — when there's a syntax error, an exception is thrown, and all the AST nodes that were created get abandoned). I guess the only other options are smart pointers and garbage collecting.

The problem with smart pointers is that I can't use the normal syntax of defining pointers (so i'll have to modify all functions and classes). Also, it seems like cpoying an object and turning all pointer dereferences to method calls would be bad for performance. The good thing is that it will flawlessly count references without mistakes without adding code to add/remove references.

The problem with garbage collection (I mean something like this: http://www.hpl.hp.com/personal/Hans_Boehm/gc/) is that I heard that it can perform poorly, and cause programs to hang occasionally for a few moments on slower computers. Also, I'm not sure if it's very portable. And finally, maybe I'm wrong, but it feels like cheating. The good thing is that I can completely forget about memory management, and don't have to modify my code (except for add/remove calls and free/delete calls). Another good thing is that the website actually mentions it being used in some programming language implementations.

Last edited by MTK358; 04-30-2011 at 12:50 PM.
 
Old 04-30-2011, 08:28 PM   #10
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443

Original Poster
Blog Entries: 3

Rep: Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723
After doing more research I decited to use the garbage collector.

I have another question, but I think that it would be more appropriate to start a new thread.
 
Old 05-03-2011, 08:29 PM   #11
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by SigTerm View Post
Typically "get" is a const method returns value without changing it, and "put"|"set" assigns new value. It is matter of taste, though. See Qt 4 documentation for examples.
Only in C++ and other object-oriented languages. There are others, you know.

For reference counting, the correct terminology is "get a reference to" and "put a reference to".

It is clearer to use "increment the reference count" and "decrement the reference count", but that will imply the argument is a reference count, not the counted object. Making that clear (for example, using inc_refcount_of() and dec_refcount_of() makes the function or method names quite long. (FWIW, I do prefer the latter two.)

"Add" is especially bad choice, since how do you "add" a reference? Does it count?

In places like the Linux kernel get/put (with respect to references) is used extensively. For example, check the first and fifth questions in the kernel module init tools FAQ. Most C books that have a chapter on reference counting I've glanced at also use get/put terminology almost exclusively.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Reference counting questions MTK358 Programming 15 03-30-2011 12:57 PM
LXer: C/C++ reference counting with atomic variables and gcc LXer Syndicated Linux News 0 05-27-2009 02:11 PM
Extending Python with C (reference counting questions) spacepigeon Programming 0 07-19-2008 09:27 AM
Time jumps by 1 day for an hour, then jumps back on RH 9? dieyouspammer Red Hat 3 04-07-2006 12:18 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:39 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration