Translate

Friday, January 25, 2013

Tutorial: How to set up Smart Pointers and TR1 C++ in the Android NDK

Optimus prime is a smart pointer.  Memory leaks?! He'll straight up kick you in the throat! This isn't Go Bots son!

What's the point


If you have ever coded in C or C++ you know you've had a memory leak some time or another. Ownership semantics are best, but sometimes those are muddy and, most of the time, the benefit of automatically reclaimed pointers far outweighs any costs (they are not much in terms of resources).

What are smart pointers?  


These are pointer containers/classes with reference counting and ownership semantics built in.  The easiest to understand and use is shared_ptr, which when all references are gone delete's the object from memory, and as expected calls the objects destructor (if it exists). For example if you create a raw pointer in a function (and don't store a reference to it anywhere else)  you would get a memory leak!


void leak_function()
{
  Sprite* sprite = new Sprite();
  // Use sprite

  // After function ends, we forgot to delete sprite :Z
}

But if we were to use a smart pointer, such as shared_ptr, we no longer have to worry about this.

Note, in this case of just using scope this smart pointer is better.

void function()
{
  std::shared_ptr<sprite> sprite =
    new std::shared_ptr<sprite>(new Sprite());

  // Use sprite

  // After function ends, sprite memory is reclaimed
}

So what happened? Once the shared_ptr went out of scope, the shared_ptr's destructor was called and its reference count was decremented.  Since the reference count was zero, it deleted itself.  Yay! Easy right?

Yeah, but it's easy to remember to delete, just do it before the end of the function.

Michael Bolton always forgets mundane details!


Sure, but there are many cases where you might want to pass a reference around to many containers, and you're not quite sure on the life time.  Especially as your project changes, sometimes you can make a mistake and your newest version has a memory leak, simply because you've forgotten some mundane detail . Using smart pointers is a cure for memory leaks (almost).


History of smart pointers in Android


These smart points sound great you say?  Ever wanted to have smart pointers in the Android NDK? How about the tr1 standards in the C++11 aka C++0x features? These features are great, but it has not been easy to get these into Android in past versions of the NDK.  

In past NDKs we would cross compile libboost for Android which contains much of the smart pointer code the TR1 standard is based on. Boost is a *great* library with loads of conveniences.  However to wrestle boost into Android, you would run into a few compile issues here and there and have to do a little exception handling trickery with the boost namespace.



This is a fine solution, using boost etc. However, I am here today to tell you a way to get all the TR1 standard C++ inclusions that are already part of the Android NDK, with no need for a reliance on a ported library. These features are not enabled in most examples you find on the NET. No problem... I am here to tell you how to grab these suckers and put them to work.

Here all the steps needed here to get you to these great C++ conveniences in your Android NDK code.

Steps to add TR1 Support for your C++ Android project:


  1. Open up jni/Application.mk 
  2. Delete or comment out any current definition of APP_STL and replace with:  APP_STL := gnustl_static 
  3. Delete or comment out any reference in Application.mk to stlport_static (you won't need it anymore) 
  4. Update to newer version of NDK without bug noted here
    1. Must be >= ndk 8d . (A bug in earlier versions of gcc in the ndk causes build issues) 
  5. Add #include   to any files that will use shared_ptr. 
  6. Add to Android.mk: LOCAL_CPPFLAGS =: -std=c++0x

Great now how do I use it?


Well for shared pointers all you need to do is #include <memory>   and reference them like so.

(I like to make a type for all my SharedPtrs):

#include  <memory>
// Your other code etc. class Sprite; //  Smart pointer type for convenience typedef std::shared_ptr<sprite> SpritePtr; Now I have a shared_ptr type definition to use like so:
SpritePtr sprite = SpritePtr(new Sprite());

Special tip:


If you have a type that you NEVER want to have a pointer to and force all instances to be in a smart pointer you can do something like this:

class Sprite
{
  // Sprite definition... blah blah

private:
  Sprite(){}

public:
  SpritePtr createSprite()
  {
     return SpritePtr(new Sprite());
  }
};

This forces all users of the class to obtain a smart pointer instance. It does negate any stack creation benefits, however (unless you override new operator etc), but that's not too important in most cases.

So that's it for now folks.  I hope you have fun not having memory leaks in your Android C++ code!

Tuesday, January 15, 2013

Emacs/Vim: Jump to errors for Java and C++ on Android

Any of you guys use vim or emacs to develop Android apps?  I sure do.  No substitute for a good editor.  Only problem is when I am doing NDK code and Java mixed (like so many others who develop games), the editor won't go to the errors in Java code since Ant formats the error output strangely.

Well fear not folks, it is an easy fix.  I usually do all my development in a Makefile that calls ant for the Java stuff and the normal ndk-build for the JNI stuff:

http://code.google.com/p/razzlegames-android-ndk-tutorial/source/browse/trunk/Makefile


You simply add the -emacs option to your ant command.  I personally bind a function key to :make in vim, and have the ant command as one of the default targets.  It ends up being called like this for debug builds:

ant -emacs  debug


Now, with this addition, Vim and emacs will jump to all your NDK and Java errors for Android development.

It's as easy as that folks!  Happy Viming!