JNI vs. C++ Object Instances - c++

I have just started at a new job. Here we are new to using JNI ( for bridging C++ / Java ). I am new to JNI so please forgive my noobness :)
In our (win32) Java app we are loading a C++ DLL. On the Java side we have several instances of "SomeJClass" each of these instances needs access to corresponding instance of "SomeCClass" on the DLL side.
The DLL exposes entry-points such as GlobalDoSomethingInC(). Here I must call the instance method of Doer::DoSomethingInC(). So I need a smooth way to map the respective this-pointers.
I also need to do the same mapping when a DLL thread discovers something interesting that it needs to notify the corresponding Java-instance of.
I can think of several solutions, but I do not like them too much. My question is, is there a better way than this ?
1 Java calls C:GetNewInstance(). This returns an int that is actually a pointer to the new C instance. Java stores it in m_myCInstance. Then Java calls GlobalDoSomethingInC(), and
1a
// DLL global
void GlobalDoSomethingInC()
{
// retrive this pointer
//calling back to Java:
jobj tmpJ = NewGlobalRef( env, obj );
Doer* myDoer = <reinterpret_cast>( Doer )tmpJ->GetMyCInstance();
myDoer->DoSomething();
DeleteGlobalRef( env, tmpJ );
// Arrrrgh
}
1b or:
// for **every call** that Java adds a parameter,
//which is the stored int:m_myCInstance, and
Doer* myDoer = <reinterpret_cast>( Doer )instanceParam->DoSomethingInC();
// Can we do better that this?
2 For calling from C to Java, things look, maybe, better
In the constructor C calls back into Java and stores
the Java instance reference
in a member variable. m_myJInstance.
In all subsequent calls m_myJInstance can be used to call back Java.
In the destructor we need to call DeleteGlobalRef( env, m_myJInstance );
Not too bad I suppose. But it really safe to store the jobject reference.
I mean: What happens when the GC moves the object around?
3 Our present solution does "work". But it belongs on rather on http://www.codinghorror.com/blog/ :)
Thanx

Typically this will depend on your environment somewhat. I've only used KNI, which is even more primitive than JNI. I think a fair bit of ugliness is unavoidable, as you're mixing memory tracking across two systems, only one of which has GC.
In general, I found it best to wrap all of the calls out the C code in functions that took care of the nasty casting, which I think is unavoidable. (BTW, I'll use C to mean non-Java code here)
On the C side, movement of Java objects is definitely a potential problem. It will depend on your platform, but I would expect that as long as you are within the lib, you can expect no Java GC to occur, so your objects are stable. YOU NEED TO BE SURE OF THIS. On the other hand, if it's not the case, you're pretty much screwed. Assuming it is the case, you want to do the same thing of isolating dereferencing/casting to the function that's exposed to JNI, so that you can happily work with normal C objects in all of your called functions.
Where it can get really ugly is if you can have objects go out of scope on either side, as then potentially either side can be holding a reference to your object. Here we used finalizers on the Java side, as well as destructors on the C side. It wasn't pretty, but I think that what somewhat unavoidable.
So, short answer, it will be somewhat ugly, isolate the ugliness around the interface between the two languages, so that for the bulk of the work, in either language, you don't have to worry about such things.
It's also worth having a base class for objects that exist over this interface, as here you can also isolate some ugliness.

jobject is an opaque handle to an object. May vary in runtime implementation (see Android 2.x vs 4.x), but just trust that it is an opaque object.
The current solution is probably correct. If you must stash a jobject in native code, you must convert it to a Global reference -- If you call NewGlobalRef, the object's refcount has increased, and will not be disposed until you call DeleteGlobalRef (and the GC has noticed it is unreachable otherwise)

Related

Pinning Unsafe pointer

I'm designing a JNI interface that passes string parameters from Java to C++. I need high performance and have been able to use Direct ByteBuffer and String.getBytes() to do that fairly well, but the penalty for passing strings to C/C++ still remains fairly high. I recently read about the Open JDK's Unsafe class. This excellent page got me started, but I'm finding Unsafe to be woefully, but understandably poorly documented.
I'm wondering, if I use the Unsafe class to obtain a pointer to a string and pass it to C++, is there a risk that the object has moved before the C++ code is entered? And even while C++ is executing? Or are these addresses provided by the Unsafe code somehow pinned? If they aren't pinned, how are these Unsafe pointers ever useful?
Unsafe is not meant to interop with JNI. So obtained via Unsafe could change any time (even in parallel with your C++).
JNI API has ability to pin object in memory to access array content (in HotSpot JVM it would block GC thus may have negative effect on GC pause duration).
In particular, Get*ArrayElements would pin array until you explicitly do Release*ArrayElements. GetStringChars work similar way.
Direct ByteBuffer hold pointer to memory buffer outside of heap, hense this buffer is not moving and you can access it for Native code.
I've read the Java source for java.misc.Unsafe and have a bit more insight.
Unsafe has at least two ways of dealing with memory.
allocateMemory/reallocateMemory/freeMemory/etc -- As far as I can tell this allocation of memory is outside the heap so faces no GC'ing challenges. I have indirectly tested this and it seems that the long returned is simply a pointer to the memory. It seems very likely that this type of memory is safe to pass through JNI to native code. And the application Java code should be able to quickly modify/query it before and after JNI calls by using some of the other intrinsic Unsafe methods that support this style of memory pointer.
object+offset - These methods accept a pointer to an object and an "offset" token to indicate where in the object to fetch/modify the value. The objects presumably are always in the Java heap, but passing the object to these methods probably helps resolve GC complications. It does sounds like the "offset" is sometimes a "cookie" rather than an actual offset, but it also sounds like that in the case of arrays, arrayBaseOffset() returns an "offset" that one can manipulate arithmetically. I don't know if this object+offset is safe for JNI code. I don't see a method to generate a pointer directly to the Java object in the heap that one could (dangerously) pass through JNI. One could pass an object and offset, but given the cost of passing Objects through JNI, this approach is not appealing anyway.
Like (1), the code associated with the page I referenced in my posting is probably pretty safe for JNI interactions. It takes the object+offset approach when dealing with String, but uses approach (1) when dealing with the direct ByteBuffer, which always reside outside the Java heap. Direct ByteBuffer's are very JNI friendly and often they can be used in ways that avoids the JNI Object passing costs I allude to in my comment to Tom above.

Should I use integer ID or pointers for my opaque objects?

I'm writing an abstraction layer on top of some graphics API (DirectX9 and DirectX11) and I would like your opinion.
Traditionally I would create a base class for each concept I want to abstract.
So in typical OO fashion I would have for example a class Shader and 2 subclasses DX9Shader and DX11Shader.
I would repeat the process for textures, etc... and when I need to instantiate them I have an abstract factory that will return the appropriate subclass depending on the current graphics API.
Following RAII, the returned pointer would be encapsulated in a std::shared_ptr.
So far so good but in my case there are a few problems with this approach:
I need to come up with a public interface that encapsulate the functionality of both APIs (and other APIs in the future).
The derived class are stored in separate DLLs (one for DX9, one for DX11 etc...) and having a shared_ptr to them in the client is a curse: on exit the graphic dlls are unloaded and if the client still has a shared_ptr to one of the graphics objects boom, crash due to calling code from unloaded DLL.
This prompted me to re-design the way I do things:
I thought I could just return raw pointers to the resources and have the graphics API clean after itself but there's still the issue of dangling pointers on the client side and the interface problem.
I even considered manual reference counting like COM but I thought that would be a step backwards (correct me if I'm wrong, coming from the shared_ptr world, manual reference counting seems primitive).
Then I saw the work of Humus where all his graphics classes are represented by integer IDs (much like what OpenGL does).
Creating a new object only returns its integer ID, and stores the pointer internally; it's all perfectly opaque!
The classes that represent the abstraction (such as DX9Shader etc...) are all hidden behind the device API which is the only interface.
If one wants to set a texture, it's just a matter of calling device->SetTexture(ID) and the rest happens behind the scenes.
The downfall is that the hidden part of the API is bloated, there is a lot of boiler plate code required to make it work and I'm not a fan of a do-it-all class.
Any ideas/thoughts ?
You say that the main problem is that a DLL is unloaded while still having a pointer to its internals. Well... don't do that. You have a class instance, who's members are implemented in that DLL. It is fundamentally an error for that DLL to be unloaded so long as those class instances exist.
You therefore need to be responsible in how you use this abstraction. Just as you need to be responsible with any code you load from a DLL: stuff that comes from the DLL must be cleaned up before you unload the DLL. How you do that is up to you. You could have an internal reference count that gets incremented for every object the DLL returns and only unload the DLL after all referenced objects go away. Or anything, really.
After all, even if you use these opaque numbers or whatever, what happens if you call one of those API functions on that number when the DLL is unloaded? Oops... So it doesn't really buy you any protection. You have to be responsible either way.
The downsides of the number method that you may not be thinking about are:
Reduced ability to know what an object actually is. API calls can fail because you passed a number that isn't really an object. Or worse, what happens if you pass a shader object into a function that takes a texture? Maybe we're talking about a function that takes a shader and a texture, and you accidentally forget the order of the arguments? The rules of C++ wouldn't allow that code to even compile if those were object pointers. But with integers? It's all good; you'd only get runtime errors.
Performance. Every API call will have to look this number up in a hashtable or something to get an actual pointer to work with. If it's a hashtable (ie: an array), then it's probably fairly minor. But it's still an indirection. And since your abstraction seems very low-level, any performance loss at this level can really hurt in performance-critical situations.
Lack of RAII and other scoping mechanisms. Sure, you could write a shared_ptr-esque object that would create and delete them. But you wouldn't have to do that if you were using an actual pointer.
It just doesn't seem worthwhile.
Does it matter? To the user of the object, it is just an opaque handle. its actual implementation type doesn't matter, as long as I can pass the handle to your API functions and have them do stuff with the object.
You can change the implementation of these handles easily, so make it whatever is easier for you now.
Just declare the handle type as a typedef of either a pointer or an integer, and make sure that all client code uses the typedef name, then the client code doesn't depend on the specific type you chose to represent your handles.
Go for the simple solution now, and if/when you run into problems because that was too simple, change it.
Regarding your p. 2: Client is always unloaded before libraries.
Every process has its library dependency tree, with .exe as tree root, user Dll at intermediate levels, and system libraries at low level. Process is loaded from low to high level, tree root (exe) is loaded last. Process is unloaded starting from the root, low-level libraries are unloaded last. This is done to prevent situations you are talking about.
Of course, if you load/unload libraries manually, this order is changed, and you are responsible to keep pointers valid.

Detecting stale C++ references in Lua

I'm lead dev for Bitfighter, a game primarily written in C++, but using Lua to script robot players. We're using Lunar (a variant of Luna) to glue the bits together.
I'm now wrestling with how our Lua scripts can know that an object they have a reference to has been deleted by the C++ code.
Here is some sample robot code (in Lua):
if needTarget then -- needTarget => global(?) boolean
ship = findClosest(findItems(ShipType)) -- ship => global lightUserData obj
end
if ship ~= nil then
bot:setAngleToPoint(ship:getLoc())
bot:fire()
end
Notice that ship is only set when needTarget is true, otherwise the value from a previous iteration is used. It is quite possible (likely, even, if the bot has been doing it's job :-) that the ship will have been killed (and its object deleted by C++) since the variable was last set. If so, C++ will have a fit when we call ship:getLoc(), and will usually crash.
So the question is how to most elegantly handle the situation and limit the damage if (when) a programmer makes a mistake.
I have some ideas. First, we could create some sort of Lua function that the C++ code can call when a ship or other item dies:
function itemDied(deaditem)
if deaditem == ship then
ship = nil
needTarget = true
end
end
Second, we could implement some sort of reference counting smart pointer to "magically" fix the problem. But I would have no idea where to start with this.
Third, we can have some sort of deadness detector (not sure how that would work) that bots could call like so:
if !isAlive(ship) then
needTarget = true
ship = nil -- superfluous, but here for clarity in this example
end
if needTarget then -- needTarget => global(?) boolean
ship = findClosest(findItems(ShipType)) -- ship => global lightUserData obj
end
<...as before...>
Fourth, I could retain only the ID of the ship, rather than a reference, and use that to acquire the ship object each cycle, like this:
local ship = getShip(shipID) -- shipID => global ID
if ship == nil then
needTarget = true
end
if needTarget then -- needTarget => global(?) boolean
ship = findClosest(findItems(ShipType)) -- ship => global lightUserData obj
shipID = ship:getID()
end
<...as before...>
My ideal situation would also throw errors intelligently. If I ran the getLoc() method on a dead ship, I'd like to trigger error handling code to either give the bot a chance to recover, or at least allow the system to kill the robot and log the problem, hopefully cuing me to be more careful in how I code my bot.
Those are my ideas. I'm leaning towards #1, but it feels clunky (and might involve lots of back and forth because we've got lots of short-lifecycle objects like bullets to contend with, most of which we won't be tracking). It might be easy to forget to implement the itemDied() function. #2 is appealing, because I like magic, but have no idea how it would work. #3 & #4 are very easy to understand, and I could limit my deadness detection only to the few objects that are interesting over the span of several game cycles (most likely a single ship).
This has to be a common problem. What do you think of these ideas, and are there any better ones out there?
Thanks!
Here's my current best solution:
In C++, my ship object is called Ship, whose lifecycle is controlled by C++. For each Ship, I create a proxy object, called a LuaShip, which contains a pointer to the Ship, and Ship contains a pointer to the LuaShip. In the Ship's destructor, I set the LuaShip's Ship pointer to NULL, which I use as an indicator that the ship has been destroyed.
My Lua code only has a reference to the LuaShip, and so (theoretically, at least, as this part is still not working properly) Lua will control the lifecycle of the LuaShip once the corresponding Ship object is gone. So Lua will always have a valid handle, even after the Ship object is gone, and I can write proxy methods for the Ship methods that check for Ship being NULL.
So now my task is to better understand how Luna/Lunar manages the lifecycle of pointers, and make sure that my LuaShips do not get deleted when their partner Ships get deleted if there is still some Lua code pointing at them. That should be very doable.
Actually, it turned out not to be doable (at least not by me). What did seem to work was to decouple the Ship and the LuaShip objects a little. Now, when the Lua script requests a LuaShip object, I create a new one and hand it off to Lua, and let Lua delete it when it's done with it. The LuaShip uses a smart pointer to refer to the Ship, so when the Ship dies, that pointer gets set to NULL, which the LuaShip object can detect.
It is up to the Lua coder to check that the Ship is still valid before using it. If they do not, I can trap the sitation and throw out an stern error message, rather than having the whole game crash (as was happening before).
Now Lua has total control over the lifecyle of the LuaShip, C++ can delete Ships without causing problems, and everything seems to work smoothly. The only drawback is that I'm potentially creating a lot of LuaShip objects, but it's really not that bad.
If you are interested in this topic, please see the mailing list thread I posted about a related concept, that ends in some suggestions for refining the above:
http://lua-users.org/lists/lua-l/2009-07/msg00076.html
I don't think you have a probelm on your Lua side, and you should not be solving it there.
Your C++ code is deleting objects that are still being referenced. No matter how they're referenced, that's bad.
The simple solution may be to let Lunar clean up all your objects. It already knows which objects must be kept alive because the script is using them, and it seems feasible to let it also do GC for random C++ objects (assuming smart pointers on the C++ side, of course - each smart pointer adds to Lunars reference count)
Our company went with solution number four, and it worked well for us. I recommend it. However, in the interests of completeness:
Number 1 is solid. Let the ship's destructor invoke some Lunar code (or mark that it should be invoked, at any rate), and then complain if you can't find it. Doing things this way means that you'll have to be incredibly careful, and maybe hack the Lua runtime a bit, if you ever want to run the game engine and the robots in separate threads.
Number 2 isn't as hard as you think: write or borrow a reference-counting pointer on the C++ side, and if your Lua/C++ glue is accustomed to dealing with C++ pointers it'll probably work without further intervention, unless you're generating bindings by inspecting symbol tables at runtime or something. The trouble is, it'll force a pretty profound change in your design; if you're using reference-counted pointers to refer to ships, you have to use them everywhere - the risks inherent in referring to ships with a mixture of bare pointers and smart ones should be obvious. So I wouldn't go that route, not as late in the project as you seem to be.
Number 3 is tricky. You need a way to determine whether a given ship object is alive or dead even after the memory representing it has been freed. All the solutions I can think of for that problem basically devolve into number 4: you can let dead ships leave behind some kind of token that's copied into the Lua object and can be used to detect deadness (you'd keep dead objects in a std::set or something similar), but then why not just refer to ships by their tokens?
In general, you can't detect whether a particular C++ pointer points to an object that's been deleted, so there's no easy magical way to solve your problem. Trapping the error of calling ship:getLoc() on a deleted ship is possible only if you take special action in the destructor. There's no perfect solution to this problem, so good luck.
This is an old question, but the right solution, IMO, is to have lua_newuserdata() create a shared_ptr or weak_ptr via either boost::shared_ptr/boost::weak_ptr or C++11's std::shared_ptr/std::weak_ptr. From there, you create a reference whenever you need it, or fail if the weak_ptr is unable to obtain lock() a shared_ptr. For example (using Boost's shared_ptr in this example since this is an old question where you probably do not have have C++11 support yet, though for new projects where possible I'd recommend C++11's shared_ptr):
using MyObjectPtr = boost::shared_ptr<MyObject>;
using MyObjectWeakPtr = boost::weak_ptr<MyObject>;
auto mySharedPtr = boost::make_shared<MyObject>();
auto userdata = static_cast<MyObjectWeakPtr*>(lua_newuserdata(L, sizeof(MyObjectWeakPtr)));
new(userdata) MyObjectWeakPtr(mySharedPtr);
And then when you need to get a C++ object:
auto weakObj = *static_cast<MyObjectWeakPtr*>(
luaL_checkudata(L, 1, "MyObject.Metatable"));
luaL_argcheck(L, weakObj != nullptr, 1, "'MyObjectWeakPtr' expected");
// If you're using a weak_ptr, this is required!!!! If your userdata is a
// shared_ptr, you can just act on the shared_ptr after luaL_argcheck()
if (auto obj = weakObj.lock()) {
// You have a valid shared_ptr, the C++ object is alive and you can
// dereference like a normal shared_ptr.
} else {
// The C++ object went away, you can safely garbage collect userdata
}
It's critical that you don't forget to deallocate the weak_ptr in your lua __gc metamethod:
static int
myobject_lua__gc(lua_State* L) {
auto weakObj = *static_cast<MyObjectWeakPtr*>(
luaL_checkudata(L, 1, "MyObject.Metatable"));
luaL_argcheck(L, weakObj != nullptr, 1, "'MyObjectWeakPtr' expected");
weakObj.~MyObjectWeakPtr();
}
Don't forget to make use of macros or template metaprogramming to avoid much of the code duplication re: static_cast<>, luaL_argcheck(), etc.
Use shared_ptr when you need to keep the C++ object alive for as long as the lua object also exists. Use weak_ptr when C++ may reap the object and it's okay for it to disappear out from under lua's feet. ALWAYS use either shared_ptr or weak_ptr when the life of an object is not known and needs to be managed automatically by refcount.
Tip: have your C++ class inherit from boost::enable_shared_from_this or std::enable_shared_from_this because it enables use of shared_from_this().
I agree with MSalters, I really don't think you should be freeing the memory from the C++ side. Lua userdata supports the ___gc metamethod to give you a chance to clean things up. If the gc is not agressive enough you can tweak it a bit, or run it manually with a small step size, more often. The lua gc is not deterministic, so if you need to have resources released then you will need to have a function that you can call to release those resources (which will also be called by __gc, with appropriate checks).
You might also want to look into using weak tables for your ship references so that you don't have to assign EVERY reference to nil to get it freed. Have one strong reference (say, in a list of all active ships) then all the others are weak references. When a ship is destroyed, set a flag on the ship that marks it as such, then set the reference to nil in the active ships table. Then, when the other ship wants to interact your logic is the same except you check for:
if ship==nil or ship.destroyed then
ship = findClosest(findItems(ShipType))
end

Wrapping unmanaged c++ in a managed wrapper

I have an unmanaged C++ library. I would like to expose the functionality for .NET applications. There's one partucular function I am not sure how to handle:
typedef void (free_fn*) (void*);
void put (void *data, free_fn deallocation_function);
The idea is that you pass dynamically allocated buffer to the function and supply a deallocation function. The library will process the data asynchronously and will release the buffer later on when data is no longer needed:
void *p = malloc (100);
... fill in the buffer...
put (p, free);
How can I expose this kind of thing to .NET applications?
Be very careful when you do this. .NET really, really wants to have its objects be pinned on the way into an unmanaged routine and unpinned on the way out. If your unmanaged code holds onto a pointer value, that had been pinned on the way in then there is very real chance that the memory will be moved or garbage collected or both.
This is especially the case with delegates marshalled to function pointers (trust me on this - I found that marshaled delegates were being garbage collected on me - I had people at Microsoft verify that for me). The ultimate solution to this problem is to stash away copies of your delegates in a static table paired with a unique transaction id, then create an unmanaged function that when called looks up the delegate in the table via transaction id then executes it. It's ugly and if I had another choice, I would've used it.
Here's the best way to do this in your case - since your unmanaged code uses a set it and forget it model, then you should make your API chunkier. Create an wrapper in managed C++ that allocates memory via an unmanaged routine, copies your data into it and then passes it on along with a pointer to an unmanaged deallocator.
In general, .NET consumers of your library won't be passing dynamically created arrays to your functions. As far as I know, all containers in .NET are garbage collected.
Regardless, you will need to make a managed wrapper for your unmanaged code. There are many tutorials and articles on this, here is one to start with.
When writing .NET wrappers for unamanged code, I've found that you want to concentrate more on preserving functionality than on making every function accessible in .NET. In your example, it may be better to just have the managed wrapper copy the array into unmanaged memory and perform whatever operations you need to inside the library. This way you don't have to do any pinning of managed memory or Marshalling of managed to unmanaged memory in order to circumvent the .NET runtime's garbage collection. However, how you implement the managed wrapper really depends on what the purpose of that function is.
If you really want to implement this function for function in .NET, you will need to look at the Marshal class in .NET for taking control of managed memory in unmanaged code.
For your callback function, you will first need to create .NET delegates that can be assigned in managed code. You will then need to make an unmanaged free function internal to your library that is called by the unmanaged version of the put function. This unmanaged free function will then be responsible for calling the managed delegate, if the user assigned one.
You definitely don't want to pin the managed buffer, as trying to deallocate it in unmanaged code seems like the shortest route to madness. If you can't rewrite this portion in fully managed code, your best bet is either going to be making a copy of the data in the wrapper, or completely hiding the buffer management from the managed world.
If you had the guts (and the masochistic stamina) you could pin the buffer in the wrapper, then pass in the marshaled delegate of a managed function that unpins the buffer. However, I wouldn't suggest it. Having had to do a couple of managed wrappers has taught me the value of exposing the absolute minimum unmanaged functionality, even if it means you have to rewrite some things in managed code. Crossing that boundary is about as easy as going from East Germany to West Germany used to be, to say nothing of the performance hits.
Most replies suggest that the data should be copied from managed buffer to unmanaged buffer. How exactly would you do that? Is following implementation OK?
void managed_put (byte data_ __gc[], size_t size_)
{
// Pin the data
byte __pin *tmp_data = &data_[0];
// Copy data to the unmanaged buffer.
void *data = malloc (size_);
memcpy (data, (byte*) tmp_data, size_);
// Forward the call
put (data, size_, free);
}
Some of the previous poster's have been using MC++, which is deprecated. C++/CLI is far more elegant of a solution.
The BEST, technique for interop, is implicit interop, not explicit. I dont believe anybody has commented on this yet. However, it gives you the ability to marshal your types from managed<->native where if you make a change to your type definition or structure layout, it will not result in a breaking change (which explicit interop does).
This wikiepedia article documents some of the differences and is a good starting point for further information.
P/Invoke (explicit and implicit)
Also, the site marshal-as.net has some examples and information as to this newer method (again, more ideal as it will not break your code if the a native struct is re-defined).
You'd have to have managed wrappers for the functions themselves (or unmanaged wrappers if you want to pass in managed functions). Or else, treat the unmanaged function pointers as opaque handles in the managed world.
Since you mentioned it was asyncronous, I'd do it this way.
The .Net exposed function only takes the data but doesn't take a delegate. Your code passes the pinned data and a function pointer to a function that will simply unpin the data. This leaves the memory cleanup to the GC, but makes sure the it won't clean it up till the asyncronous part is done.

C++ Memory management

I've learned in College that you always have to free your unused Objects but not how you actually do it. For example structuring your code right and so on.
Are there any general rules on how to handle pointers in C++?
I'm currently not allowed to use boost. I have to stick to pure c++ because the framework I'm using forbids any use of generics.
I have worked with the embedded Symbian OS, which had an excellent system in place for this, based entirely on developer conventions.
Only one object will ever own a pointer. By default this is the creator.
Ownership can be passed on. To indicate passing of ownership, the object is passed as a pointer in the method signature (e.g. void Foo(Bar *zonk);).
The owner will decide when to delete the object.
To pass an object to a method just for use, the object is passed as a reference in the method signature (e.g. void Foo(Bat &zonk);).
Non-owner classes may store references (never pointers) to objects they are given only when they can be certain that the owner will not destroy it during use.
Basically, if a class simply uses something, it uses a reference. If a class owns something, it uses a pointer.
This worked beautifully and was a pleasure to use. Memory issues were very rare.
Rules:
Wherever possible, use a
smart pointer. Boost has some
good ones.
If you
can't use a smart pointer, null out
your pointer after deleting it.
Never work anywhere that won't let you use rule 1.
If someone disallows rule 1, remember that if you grab someone else's code, change the variable names and delete the copyright notices, no-one will ever notice. Unless it's a school project, where they actually check for that kind of shenanigans with quite sophisticated tools. See also, this question.
I would add another rule here:
Don't new/delete an object when an automatic object will do just fine.
We have found that programmers who are new to C++, or programmers coming over from languages like Java, seem to learn about new and then obsessively use it whenever they want to create any object, regardless of the context. This is especially pernicious when an object is created locally within a function purely to do something useful. Using new in this way can be detrimental to performance and can make it all too easy to introduce silly memory leaks when the corresponding delete is forgotten. Yes, smart pointers can help with the latter but it won't solve the performance issues (assuming that new/delete or an equivalent is used behind the scenes). Interestingly (well, maybe), we have found that delete often tends to be more expensive than new when using Visual C++.
Some of this confusion also comes from the fact that functions they call might take pointers, or even smart pointers, as arguments (when references would perhaps be better/clearer). This makes them think that they need to "create" a pointer (a lot of people seem to think that this is what new does) to be able to pass a pointer to a function. Clearly, this requires some rules about how APIs are written to make calling conventions as unambiguous as possible, which are reinforced with clear comments supplied with the function prototype.
In the general case (resource management, where resource is not necessarily memory), you need to be familiar with the RAII pattern. This is one of the most important pieces of information for C++ developers.
In general, avoid allocating from the heap unless you have to. If you have to, use reference counting for objects that are long-lived and need to be shared between diverse parts of your code.
Sometimes you need to allocate objects dynamically, but they will only be used within a certain span of time. For example, in a previous project I needed to create a complex in-memory representation of a database schema -- basically a complex cyclic graph of objects. However, the graph was only needed for the duration of a database connection, after which all the nodes could be freed in one shot. In this kind of scenario, a good pattern to use is something I call the "local GC idiom." I'm not sure if it has an "official" name, as it's something I've only seen in my own code, and in Cocoa (see NSAutoreleasePool in Apple's Cocoa reference).
In a nutshell, you create a "collector" object that keeps pointers to the temporary objects that you allocate using new. It is usually tied to some scope in your program, either a static scope (e.g. -- as a stack-allocated object that implements the RAII idiom) or a dynamic one (e.g. -- tied to the lifetime of a database connection, as in my previous project). When the "collector" object is freed, its destructor frees all of the objects that it points to.
Also, like DrPizza I think the restriction to not use templates is too harsh. However, having done a lot of development on ancient versions of Solaris, AIX, and HP-UX (just recently - yes, these platforms are still alive in the Fortune 50), I can tell you that if you really care about portability, you should use templates as little as possible. Using them for containers and smart pointers ought to be ok, though (it worked for me). Without templates the technique I described is more painful to implement. It would require that all objects managed by the "collector" derive from a common base class.
G'day,
I'd suggest reading the relevant sections of "Effective C++" by Scott Meyers. Easy to read and he covers some interesting gotchas to trap the unwary.
I'm also intrigued by the lack of templates. So no STL or Boost. Wow.
BTW Getting people to agree on conventions is an excellent idea. As is getting everyone to agree on conventions for OOD. BTW The latest edition of Effective C++ doesn't have the excellent chapter about OOD conventions that the first edition had which is a pity, e.g. conventions such as public virtual inheritance always models an "isa" relationship.
Rob
When you have to use manage memory
manually, make sure you call delete
in the same
scope/function/class/module, which
ever applies first, e.g.:
Let the caller of a function allocate the memory that is filled by it,
do not return new'ed pointers.
Always call delete in the same exe/dll as you called new in, because otherwise you may have problems with heap corruptions (different incompatible runtime libraries).
you could derive everything from some base class that implement smart pointer like functionality (using ref()/unref() methods and a counter.
All points highlighted by #Timbo are important when designing that base class.