Monthly Archives: April 2013

Game development irony

The guys at http://www.greenheartgames.com/ pulled a nice trick yesterday. Just the day after they released their game development simulation game Game Dev Tycoon, they also uploaded a cracked version of the game for the pirates.

What the heck ! What for ?
Well, this cracked version is the same as the original game except the players are screwed, they cannot expand their in-game company above some limit due to …

Hum, well … Yes, piracy … Ironic, isn’t it ?

This really made my day :-) I haven’t tested the game itself yet but it sure looks like fun.

std::unique_ptr semantics

Probably the best feature introduced by C++11 is std::unique_ptr. It will automagically make sure your dynamically allocated objects are deleted when you don’t use them anymore.

In previous versions of C++, you needed to rely exclusively on documentation and conventions to ensure dynamically allocated memory was handled properly. With C++11, you can ask the compiler to help you out and enforce ownership semantics. Take the following code for example, you need to ensure you call delete when you are done with the object created by function factory(). The compiler will not complain if you forget and you end up with a memory leak.

What can std::unique_ptr do for you ?

With std::unique_ptr, you cannot casually forget to delete the pointer. std::unique_ptr owns the allocated object unless this ownership is explicitly transferred to another entity (eg. another unique_ptr, a std::shared_ptr). When a std::unique_ptr goes out of scope, it will delete any object it owns.

The most explicit way of transferring ownership is via function std::move(). Using the same above example, we can see how it works.

You cannot directly assign an instance of std::unique_ptr to another. This rule ensures that no two unique_ptr can claim ownership of the same dynamically allocated object. It prevents deleting an object multiple times.
This is the magic of std::unique_ptr, you always know who owns the pointed value. By consistently using unique_ptr, you know at a glance when you own a heap object and when you yield ownership to another. Moreover, this rule is enforced by the compiler — the less you need to worry about, the better.

How do you use std::unique_ptr ?

std::unique_ptr helps you express your intent with regards to ownership transfer. Transfer of ownership occurs in the following general cases :

  • Returning a dynamically allocated object from a function
  • Passing a such an object to a function

Returning a std::unique_ptr

Returning a heap-allocated object from a function requires that the caller delete it when it is done with.

By returning a unique_ptr, you ensure the caller takes ownership of the pointed object. In the example below, the signature of createVector() ensures the caller takes the responsibility for releasing the created vector. Normal flow of execution guarantees memory will be released whenever the returned unique_ptr is destroyed.

Passing a std::unique_ptr to a function

A function taking a unique_ptr takes definitive ownership of the pointed object. The caller will not even have the ability to access the pointed object after the function call.
Notice the call to function std::move(), it is required and helps you actually see that ownership is transferred to the function.

Passing a const reference to a unique_ptr

The called function can use the pointed object but may not interfere with its lifetime. The caller function keeps ownership of the pointed object.

In my opinion, there is no real benefit to using a const reference to a unique_ptr from simply using a raw pointer to the object. On the contrary, it introduces a constraint on the caller that it must manage the pointed object through a unique_ptr. But what if your caller context requires you have shared ownership (std::shared_ptr)? Since we mostly care about whether ownership is transfered (not how ownership is cared for), a raw pointer is perfect.

Passing a non-const reference to a unique_ptr

This is, in my opinion, the most complex situation. The called function may or may not take ownership of the passed pointer. “may or may not” is really part of the functions contract. If the called function uses std::move() on the passed unique_ptr, it effectively takes onwnership and once it gives control back to the caller, the caller does not own the pointer anymore, it doesn’t even know the value of the pointer anymore. On the other hand, if the callee merely uses the provided pointer without moving it, the caller still owns the pointed object.

Conclusion

C++11 provides us with a great tool for managing the lifetime of dynamically allocated object. When used consistently, std::unique_ptr lets your code really express when ownership of a dynamic object is transferred and in which direction directly. The compiler will even see that the semantics are respected at compile-time.

However, they are of no use when you don’t intend to express ownership semantics. Pass raw pointers whenever you can but make sure that you use std::unique_ptr or another similar smart pointer when you mean to transfer ownership.

boost::serialization coupling issue

I was evaluating boost::serialization today. Based on the design goals mentioned in the library’s introduction, I felt like boost::serialization would suit my needs.

An interesting point is this :

8. Orthogonal specification of class serialization and archive format. That is, any file format should be able to store serialization of any arbitrary set of C++ data structures without having to alter the serialization of any class.

At first, I interpreted it as an intent to decouple the serialization code (that knows about the object’s internals) and the archive format.
Consider this:

All is fine, ClassA does not know the specifics of type Archive. Any object implementing the Archive concept will do just fine.

Yet, I have a problem with this. Inline code in headers has a tendency to irritate me. It hides the structure of the classes you implement so I often use the PImpl idiom.
I want to (or must in the case of PImpl) move the implementation to ClassA.cpp.
But … can I ?

serialize() is a template method. Can I forward declare a template method ? Well, yes.

In ClassA.hpp :

In ClassA.cpp:

In main.cpp, try to serialize an instance of ClassA :

Compile and link :

1
2
3
4
5
g++ -c main.cpp -o main.o
g++ -c ClassA.cpp -o ClassA.o
g++ main.o -lboost_serialization -o program
main.o: In function <code>void boost::serialization::access::serialize&lt;boost::archive::text_oarchive, classa=""&gt;(boost::archive::text_oarchive&amp;, ClassA&amp;, unsigned int)':
main.cpp:(.text._ZN5boost13serialization6access9serializeINS_7archive13text_oarchiveE6ClassAEEvRT_RT0_j[_ZN5boost13serialization6access9serializeINS_7archive13text_oarchiveE6ClassAEEvRT_RT0_j]+0x25): undefined reference to

void ClassA::serialize<boost::archive::text_oarchive>(boost::archive::text_oarchive&, unsigned int)’
collect2: error: ld returned 1 exit status
make: *** [program] Error 1
Does this compile ? Yes. Does this link ? … No!

What’s the compiler trying to tell me ? Undefined reference to ClassA::serialize(…). But I defined it, no ?
Well, yes and no. You wrote the code but it is a template function. So it needs to be instantiated at compile-time. When main.cpp is compiled, it sees the forward-declaration of ClassA::serialize() and assumes that the linker will find the implementation of void ClassA::serialize<boost::archive::text_oarchive>(boost::archive::text_oarchive&, unsigned int) somewhere.
But it does not because, ClassA.cpp while implementing the template function does not instantiate it. ClassA::serialize() is parsed but never compiled into actual machine code.

You can check for yourself. Look at the file size :

1
2
-rw-rw-r-- 1 timoch timoch 940 Apr 12 12:59 ClassA.o
-rw-rw-r-- 1 timoch timoch 143088 Apr 12 12:59 main.o

940 bytes ? That’s not a lot.

You can force the instantiation of ClassA::serialize() in ClassA.cpp. Add the following at the end:

It works, but is it good ? Not to me.

I need to include a header defining the implementation of the specific format I serialize to. I also need to include text_iarchive.hpp for the loading process to work. Tomorrow, when my object needs to be serialized to another format as part as another use case, I will need to modify its implementation file to include the specifics of that other format. I will need to do this for each and every class to be serialized … not something I would enjoy.

 

Conclusion

 

Templates provide a huge flexibility. Here it is used to enable the & operator to serve as both an extract and inject operator. However, it is at the expense of forcing the client application to put the saving/loading implementation in the same compile unit as the definitions of your target format. It completely voids the efforts put toward decoupling the serialized objects and the format they serialize to.

There are ways to achieve the same flexibility of ‘same operator’ saving and loading while preserving decoupling with the serialization format. I will come back to that in a later post.