Engineering Game Development

Lee Winder, Technical Manager at BlitzTech on Software Engineering, Game Development and Education

I’ve wanted to blog more about our internal STL implementation for a while and one of the interesting things I wanted to cover was how we implemented the STL deque, which I think is a sometimes misunderstood and unfortunately not a very often used container.

But first, what is a deque.

A good place to start is to say it’s pronounced ‘Deck’ and is short hand for ‘double ended queue’, giving you an idea of what it’s main strengths might be. Like a vector it offers constant time operations when adding or removing from the back, but unlike the vector it also offers the same when adding or removing from the front, making it a perfect container for queue style containers.

And it’s this later ability that makes it vastly different from a vector than the interface might otherwise suggest.

One major missing set of functions is something that you should always be using by default on a vector – reserve() and capacity(). And those missing functions should indicate an underlying difference in the way memory is allocated.

An STL implemented deque usually allocates memory in pools which are able to contain N number of entries in the container. Exceed the number that can fit in a pool and another pool is created, linked to the previous one. This gives it the ability to add values to the front and back of the container, in effect creating a chunky link list structure internally.

And it’s a good idea. By enabling a chunky (or sometimes not so chunky) list structure you have less of a need to preallocate memory, inserting values leans more towards a fixed, or more predictable, model and you lose the spikes that often accompany a vector should you keep extending past the current capacity.

But it’s not perfect. And it’s primary strength can also be it’s primary weakness.

Game developers like static memory. They like to allocate memory and stick with it. They don’t like memory that is allocating left, right and centre and they don’t like to have to guess at whats been allocated and when. Consoles like static memory too, and they like memory to be in the general vicinity of memory they are already looking at.

Coming from this, game developers and consoles generally don’t like link lists (though that’s not to say we don’t use them when we need to). And if we have to use them, it’s good to explicitly use them, or even better to use an intrusive list instead (more on those another day).

But surely you can be a bit clever. Maybe setting the size of a pool to be how ever many elements you want to add, in other words trying to mimic reserve(). But then you still need to allocate more memory when you add to the front, or the back, or where-ever depending where your particular implementation of a deque drops in the first elements (and since there is nothing guiding the implementation in the standard it could be anywhere).

And some implementations (Visual Studio I am looking squarely at you) have horrific ways of specifying how big these pools should be and simply do not provide the flexibility you need when working with them.

So what did we want and how did we approach implementing our own Deque container?

The first thing we wanted was our reserve and capacity back (along with our custom resize_capacity and other related functions) because that gives programmers vital control over what’s being allocated and when. Granted you could probably get similar behaviour by using a different allocator, but we don’t want to have to use a unique allocator 99% of the time!

As a result (and it’s a good one) that leads us back to having a block of continuous memory allocated within the deque which can make traversing the container much more cache friendly and makes memory management much easier. It also removes the question of “if I remove this element will the memory layout change?”. We’re sticking with vector style memory, which dictates that memory will not be freed unless specifically requested, another feature that ties in with developers needing to be confident of what their containers are doing.

This also allows us to lead quite easily towards a fixed::deque container with the same interface and very similar behaviour which is much harder with the chunky linked list approach.

But obviously a vector has this memory layout, and doesn’t have constant time insertion at the start of the deque. So something needs to be different?

A Ring Buffer is a pretty common data structure in computer science and fits the bill perfectly. Add an element to the back or front, and simply wrap around the available heap until your buffer start/end hit each other. At that point either stop accepting new entries (as a fixed deque would) or allocate additional memory and keep adding (in our case we increase the allocated size by 50% to keep it consistent with the vector).

This allows us to have constant time insertion at the start/end but it does make our iterators a bit more complicated as they need to be aware of their heap and buffer boundaries, but that’s only a few pointers so it’s not to bad (and traversing linked lists using iterators isn’t much different so it’s not much of a trade off).

Obviously going down this route has it’s downsides. Inserting elements one after another without reserving is much slower but developers shouldn’t be doing that anyway and most importantly traversal of the deque is much improved. Benchmarks on the platform we develop for at work show an increase in traversal speed in the order of 100% on some platforms, with the worst being around 30% faster which is nothing to sniff at.

But a fundamental change like this does means that people coming to this Deque when they are intimately familiar with a std::deque will either miss the sometimes small tweaks and use it inefficiently or be thrown by what they see and be less inclined to use it. But decent documentation and mentoring can easily overcome those hurdles.

From the outset memory management and traversal were the areas we were most concerned about when looking at the ftl::deque, and while insertion is certainly slower if you don’t reserve (though no-one should be using an FTL Deque without reserving memory before hand) this is a price I’m quite happy to pay.

Title image by mdezemery

One of the most difficult things when it comes to unit testing is cutting down on the number of duplicated tests. In the past I’ve often developed objects which have very different implementations but externally produce very similar results (for example when developing a vector compared to a fixed vector, or implementing different types of iterators), and one thing I don’t want to do is have a set of tests which are almost identical to another set of tests I wrote last week.

One method I’ve used is to write a common set of tests independent of a specific type and had the type defined in another file, along with other flags which are used to indicate which tests should or shouldn’t be run.

So for example, when developing a ring buffer style iterator, it was useful to know that the const and non-const versions produced the same results in a lot of different situations without having to have comparison tests or duplicating a large amount of test code.

The following examples are written using UnitTest++ but will work with a number of different unit testing Frameworks

// In the file RingBufferIterator_Tests.inl

// Tests are defined in a separate file assuming certain
// settings have been defined
TEST(Blah)
{
RINGBUFFER_ITERATOR_TYPE myItor;

//...  Doing tests with this type
}

Now we simply need to define the type of iterator and indicate if some tests should or shouldn’t be run

// In the file RingBufferIterator_TestTypes.cpp

SUITE(RingBufferItor)
{
// Define the type of iterator we want to test
#define RINGBUFFER_ITERATOR_TYPE ftl::itor::ringbuffer

// Define a couple of settings which the tests file uses to make
// sure some type specific tests are run or excluded

// This one simply indicates that the tests checking the ability
// to alter the content of the iterator will be run
#define RINGERBUFFER_ITERATOR_NONCONST_CONTENT

// Now we simply need to include the file used to
// implement all the unit tests for this kind of iterator
#include "RingBufferIterator_Tests.inl"
}

We do the same for the const version of the iterator we are testing

// In the file RingBufferConstIterator_TestTypes.cpp

SUITE(RingBufferConstItor)
{
// Define the type of iterator we want to test
#define RINGBUFFER_ITERATOR_TYPE ftl::itor::ringbuffer_const

// In this case we don't have any additional settings so we
// simply include the test files and let the tests run
#include "RingBufferIterator_Tests.inl"
}

You can take this as far as you want but there is obviously going to be a point where the number of flags you’re defining starts to make the tests hard to read or unmanageable. Limiting it to about two, where you can easily group the tests within these defines generally works quite well.

You don’t need to limit it to a single file. For example, some types might be similar enough to share 50% of the tests but not the rest. Splitting up the common tests is easy enough.

// In the file VectorContainer_TestTypes.cpp

SUITE(Vector)
{
// Define our type
#define VECTOR_TYPE ftl::vector

// Include our common tests
#include "Vector_CommonTests.inl"

// Include only the tests for this type
#include "Vector_DynamicTests.inl"
}

When tests are not written like this there is a a big gap in the ability to test if comparable types behave the same (fixed and non-fixed containers for example) especially when simple things like human error can get in the way of creating duplicate behaviour tests. By changing over to this style of testing we can automatically test the behaviour of similar types without creating additional work.

It does have it’s draw backs, the main one being that you can get multiple test failures (if a test is used by >1 type and they both fail at the same time) or worse you get one fail and you’re not sure which type caused the problem. An easy solution to this would be to allow the failure message to have a option component, allowing you to identify the type in the message, but this isn’t supported by any test framework that I know of.

Occasionally my compilers dependancy checker doesn’t cope very well, compiling only one of the type files rather than all of them if a test changes, but this has been remarkably rare and these draw backs don’t overshadow the ability to confirm that your types are functionally the same even if their implementation is vastly different.

Well it didn’t take a long as I’d feared, so now this blog post is coming to you from www.leewinder.co.uk. Unfortunately, I don’t have anything interesting to say in this one as it’s more of a test for me to make sure everything is working and the original FeedBurner feed is still good.

This should still work with the old address to, but if you’re accessing the site through that, it might be a good idea to update any links as it won’t be staying this way forever.

Unfortunately it looks like e-mail on this domain isn’t working which I’ve had to raise with my host provider, but other than that it seems to have done down well.

I’ve a couple of blog posts planned for the near future (one every 2 weeks would be a good thing to aim for I think) that go over unit testing, coding standards and the IGDA, and I’ve love to post something on why it seems everyone I follow on Twitter hates C++, but maybe that’s a can of worms that needs keeping shut…

Anyway, I’ve taken up enough of your time with this (far to long) ‘test’ post so I hope you enjoy your weekend.

I recently bought a Mac. I wanted a small, easy to use media centre to sit next to my TV and while I originally looked into getting a Dell Zino I thought it’d be a perfect time to get an unintrusive Mac and headed off to the Apple Store and picked up a Mac Mini.

So far I’m loving it (even after having to return the first Mini due to a faulty graphics card and then the wireless keyboard due to a faulty space bar!) and as an introduction to Mac’s it’s been worth it. I don’t really do anything ‘Maccy’ on it other than use XBMC, browse the internet and use Aperture but I’m actually enjoying the experience rather than wanting to throw the machine out of the window (having said that, I’ll still dual boot to Windows should I want to do any hobby development with XNA).

Since I was so impressed with it, I thought it’d be worth trying to install Mac OS X on my little Dell Mini 9. I love my Mini 9 but even with a fresh install it’s been struggling even running Windows XP (taking 10 minutes to boot up(!), constantly freezing and generally being pretty naff). Installing OS X, I hoped, might give it a bit of a kick up the backside.

I also network the two machines, using the Dell as a little media server and Time Machine seemed to meet my server back up needs and it’s free out of the box. What’s not to like?

I was worried that this would involve kernel hacking, boot strap loaders, luck and quite a bit of swearing but surprisingly it was stupidly easy… Following the Hackintosh instructions for the Dell Mini 10 resulted in a Mac powered Mini 9 in about 90 minutes.

But then things got a little bit complicated. Anyone keeping track of the Hackintosh ’scene’ will know that OS X 10.6.2 dropped support for Atom processors, put it back in, then dropped it in the final release, which would mean no OS X on my Dell Mini. But not updating an OS isn’t really that good an idea.

A few quick hits on Google brought up a possible hack. Changing various kernel files, kernel panics (seriously I’d panic trying this) and any other number of things that can go wrong (I’m not worried about anything breaking because it’s not going to be the end of the world. I just don’t really have the time to try and figure out what I need to do and do it, rather than it just working out of the box).

But there really are some cool people on the internet. Using NetBook Installer (a sister project to the Netbook BootMaker tool which was used to install OS X in the first place).

Updating from OS X 10.6.0 to 10.6.2 was as simple as

(I probably didn’t need to run Netbook Installer the first time but it only take 5 minutes).

And literally that was is. A smooth copy of OS X 10.6.2 running on my compact Dell Mini 9 as a quiet, low power media server.

It’s all good.

(It might be noticed that I’ve not been blogging much recently. I’ve not run out of things to say it’s just that with moving house, Christmas and lots (and lots) of DIY, the time has just not been there. Service will resume at some point – soon)

Unity builds. I don’t like them.

Of all the tools at your disposal to make a build faster, this is the worst. And it’s not just the “hey let’s #include .cpp files” weirdness, but the way that it can make a well structure, modular code base become worse than spaghetti junction at rush hour, and the worse thing is that it’s not the fault of the programmer, especially when something as exceptional as Visual Assist can start helping you create non-modular code because of the way Unity Builds collect the code you write.

What Is a Unity Build?
Unity Builds have nothing to do with the excellent Unity Tool Set. I’ll just clear that up right off the bat.

These Unity Builds are a way of reducing build over-head (specifically opening and closing files and reducing link times by reducing the number of object files generated) and as such are used to drastically speed up build times. I say drastically because they are usually used after a code base has starting generating build times that totally cut down on a programmer’s productivity. This might be 10 minutes, 30 minutes or even hours.

Because Unity Builds give you a quick gain, it’s seen as a pretty magical solution, and when a full build is reduced from 30 to 3 minutes you can see why. But the caveat in that statement? Full builds.

I won’t go through how to generate Unity Builds here as the blog post The Magic of Unity Builds does a great job so have a look there. It’s interesting that I’m linking to a blog post that is in the total opposite direction that I’m coming from, but unless you know both sides of a tale, you don’t know the tale.

So without any more delay, why don’t I like them?

Say Goodbye to Local Properties
Well written code is modular, and modular code relies on a few assumptions. One of those being that a single translation unit (a cpp file and any associated include files) is isolated from other translation units, so (unless you extern the contents) anything defined within a cpp file is not available outside, and as a consequence you can have local objects being called the same things without conflict.

Take for example the following simple code (easily expanded to a real world example I’m sure)

// In VectorTest.cpp
namespace
{
   const uint StandardTestCount = 10;
}
// In ListTest.cpp
namespace
{
   const uint StandardTestCount = 3;
}

In a normal compilation environment these variables are local to the file they are working in, and this is a good thing. Why should the vector tests file care what is defined within another test file?

But if you have a Unity Build with the following then you’re going to have issues…

#include "VectorTest.cpp"
#include "ListTest.cpp"
#include "ArrayTest.cpp"
#include "QueueTest.cpp"

Specifically errors relating to the variable ::StandardTestCount already being defined. So we now have to be aware of what is defined throughout the entire project and resolve any issues, and inevitable this will end up with all variables being pre-appended with (in this example) VectorTest_ and ListTest_ etc.

I don’t want to refer to the ‘Magic’ post to much, as it’s a good article, but there is a statement in there referring directly to this. Specifically the following

“Technically you shouldn’t have this problem if you’re writing “proper” code”

This is wrong. “Proper” code is well structured and well maintained, meaning it’s modular and only refers to what it needs to refer to. In a lot of cases you will have variables with the same name, functions with the same name and other elements that you naturally write as you go along. That’s why the anonymous namespace (or the C style ’static’) is so useful, and so useless if you switch to Unity Builds.

Using Is (even more) Lethal
Never use the ‘using’  keyword in a header file. It’s a standard statement and one that stands up easily. The reasons behind this are pretty clear (declaring ‘using’ in a header file forces all code including the header file to use that statement – in effect wiping out a namespace).

But using it in a .cpp file isn’t a crime. In fact it’s remarkably useful, even within the whole files scope. As a developer, I should know what I’m using in a local file, what elements I’m bringing into the file and what would/could conflict. Some people might not agree that ‘using’ at the top of a cpp file is a good idea at all, and I see their point, but on a whole file scope, it can be massively useful and as it’s localised it’s not going to pollute anything other than the file it’s in.

But in Unity Builds, using (that is not scoped within a function or type etc.) is lethal. Declaring ‘using ‘ in a cpp file makes it available throughout the code base (or more confusingly only in those files that are included after the one declaring it). Suddenly, using is everywhere. And your namespaces are now useless.

Every Change is a Rebuild
This is one of my biggest problems with Unity Builds. In well structured projects (more on that below) changing the content of a cpp file (or even a local header file) shouldn’t require everything to be rebuilt. Every. Single. Time. Yes, the unity build rebuilds are faster than doing a full build without a unity file, but doing even a fast rebuild every time will build up. Quickly.

When-ever I change a .cpp file, all I need to build is that .cpp file. Granted, link times are a tad long because it still has to re-link the other object files, but it takes a second to compile that one file. On average (I took count today) when I changed a header file it compiled on average 5 .cpp files. And it (again on average) took about 5 seconds to build.

Very rarely should I be required to re-build the entire project, and most of the time I’m don’t. And that saves me a lot of time. Every single day.

Multiple Configurations
This is mainly a bugbear of mine rather than a direct issue with Unity Builds, but I see it in nearly every Unity Build project I use. The main project is the Unity Build project, but there is another project that is built and maintained that doesn’t use Unity Builds. Now there is a point here – by having an additional ‘normal’ project you are forcing the modularity that can collapse with Unity Builds to be checked (usually a Continuous Build server will be building this as well as the Unity Build every time).

But we have problems with this.

Firstly, the non-unity build is only ever being built on the CB server. So any problems are going to break the build, and it will break if people are not using it day-to-day. Secondly you now have multiple projects to maintain. Not too much of a problem if you have an automated project generation step (see below) but it is still another project to maintain.

People may occasionally have to use the non-unity configurations, especially if they are getting an unknown error on the CB server. So now they are left working on a configuration that is uncared for and probably builds so slowly and erratically that they are probably losing all the time they saved from those quick unity builds they have been doing all day.

But What About My Build Times Then?
Well structured software builds quickly (or as quickly as they can anyway). But what is a well structured project when it comes to build times?

  • Sensible file inclusion – Only include the files you need and try as best you can to limit them to .cpp files. This means the compiler only needs to bring in what’s necessary and when you change one of these header files only those things that directly rely on it will change. If you find yourself having to include files that constantly change into a large number of cpp files, then I’d wager that a refactoring of the large header file would be in order. You should be building only a small number of cpp files when you change the content of a header file.
  • Forward Declarations – Where possible use forward declarations rather than including the header file in your class or function declaration. Annoyingly you cannot forward declare enums (on standard compliant compliers anyway) which sometimes throws this out of the window. But by not including the files until use, you’re cutting down on the amount of code being included and the number of files being opened.
  • Pre-compiled Headers – Use Pre-compiled Headers (PCH). Using PCH’s is the one (built into the IDE) feature that will cause your build times to plummet, especially if you are being sensible with them (such as including files that don’t change – SDK’s and common, fixed headers for example). Using pre-compiled headers across multiple platforms can be a pain, but it is possible to unify them and get a massive boost. I’ll cover these a little bit more below.
  • Library Files – Modular code usually leads towards easily extracting common code into a collection of libs. Reducing the amount of code in a project (and as a result how much you need to build) can speed up your productivity quickly.
  • Parallel Building – If you’re IDE supports it (and it might do and you just don’t know) and you have a multi-core machine, turn on parallel building of files. Building individual files at the same time is obviously going to cut down on your compile times no matter how quick they are at the moment.
  • Get a Better PC – It goes without saying (but I will anyway) doing this will speed everything up.

Pre-Compiled Headers
Pre-compiled headers are one of the best ways to get a massive boost to your compile times. So how fast are my build times compared to that of a Unity Build version when using PCH’s and taking into account the other build improvements suggestions?

As stated above the ‘average’ build time of a minimal build throughout the day was around 5 seconds. On a Unity Build it was a full build every time and was around 2 minutes on the slowest platform.

Changes to ‘core’ files, which are included by a higher than average number of files, resulted in builds of around 30 seconds on around 20 files. Again on a Unity Build this would have been around 2 minutes regardless.

Full rebuild (which I did twice today) was around 3 minutes. Granted a whole minute slower than a Unity Build but I did it twice rather than every single time.

Pre-compiled headers are not a silver bullet solution. Nothing is. And because of this here are issues that you do need to be aware of

  • Compiler Support – Some compilers out there simply do not support PCH’s. On a daily basis I use between 4 or 5 different compilers and while I’ve never encountered one that doesn’t, they are out there. This can shoot my argument in the foot, but it is a rare problem and one most people won’t encounter.
  • PCH Quirks – While I use a number of compilers that do support PCH’s, every single one of them has a slightly different way of building them and slightly different requirements before they can be used. This doesn’t affect the code that is written but does affect the content of your project, especially if you want to make them seem as consistent as possible.
  • Over-Inclusion – Because your PCH usually includes common files and files that rarely change, it does mean that some files are being brought into the project in a compilation unit that wouldn’t otherwise be required

Unity builds are a solution for the wrong problem. Long compile times are not caused by not using Unity Builds, they are the result of having badly structured and badly referenced code. Fix that (and have better code to boot) and you’ll be able to use ‘proper’ build tools without resorting to a quick fix.

Making Unity Builds Better
I don’t want to just leave it at that, because no matter how much I argue, Unity Builds will always exist and people will always use them (after all it’s quicker to rescue a broken down build by making it a Unity Build than doing it the hard way). So what can people do to actually make Unity Builds a bit more desirable and less of a problematic fix?

  • Automate Adding Files – A lot of teams have auto project generation code already (XML files, template projects etc.) so it’s important that you automate adding files to the project, otherwise people will forget to remove the file from the build step and they will forget to add it to the unity build file.
  • Multiple Unity Files – Running a Unity Build doesn’t require you to have one unity file with every cpp file inside it. You can have multiple build files (usually per module or per component) which means at least some of the translation unit leaking is limited to each module rather than the whole program.
  • Additional Project – No, this isn’t a contradiction from the above “Multiple Configurations” comment above. In this situation you will have a project that contains the cpp and header files so you can reference them but this project isn’t built. Instead, you have the ‘proper’ project simply contain the unity file(s). This isn’t something I’ve personally tried, but it does get around the issues of adding files if you don’t have an automated step.

SAFE_DELETE and SAFE_FREE. What do those functions (macros?) say to you? What if you also have over-ridden calls to DELETE and FREE too?

I think most people see a safe delete function as one that handles a null pointer safely – only calling delete or free when the ptr isn’t null. Since this is totally irrelevant (‘delete null’ is a no-op as defined by the standard and free(null) seems to be just as safe) there’s nothing special or even needed here.

So the ’safe’ part must be something else?

What about the usual delete/free over-ride behaviour of setting the pointer to the free’d memory to null itself. Well, that’s just common sense. No-one wants dangling pointers left lying around as that way only leads to memory over-rides and random crashes (usually in the submission candidate build 10 minutes before it needs to be uploaded). So if that’s the reason, then to be honest the macros should be called SENSIBLE_FREE or REASONABLE_DELETE. But then that’s just daft.

I suppose you might have a situation where setting it to NULL isn’t really necessary.

delete myPointer;
/* myPointer = NULL */ // Don't need this now

myPointer = new SomeClass;

But seriously, is having an extra line setting ‘myPointer’ to NULL a problem in the grand scheme of things? Any half decent compiler would probably strip it out anyway, and besides you’re freeing and allocating memory – an assignment isn’t going to mean squat in the middle of that.

Thinking some more, you might also have a const pointer, that cannot be set to null. This, I suppose, is an issue, but it’s an interesting one, that gets into the realms of what’s a const pointer (or a pointer to const data) represents to the user? I don’t want to cover that here, as it could take pages and pages (and generate lots and lots of comment), but it’s a case that is rare and isn’t something that should be seen as ‘the norm’.

Another possibility is that these ’safe’ functions are doing a little extra. Maybe in debug, the heap code is checking that this pointer was actually allocated in the same heap you are trying to free it from, or if indeed it was allocated at all. Safe in this context seems to be more like ‘close your eyes and hope for the best’ kind of safe. It’s all good and well being safe in debug, but I’m guessing code like this isn’t run in master builds, so you’re left with finding problems in master, when it becomes so much harder to track down issues of any kind. It’s much better to have these problems flagged at the earliest opportunity, so doing these kinds of checks in a vanilla over-ride makes more sense than doing it in a ’safe’ version.

So really, there is nothing ’safe’ about functions like these, nothing they do that wouldn’t be carried out by a programmer in their day to day work. So why do so many libraries have different versions of an over-ridden function, ones which are ’safe’ and one’s which, apparently, are not.

So just bite the bullet and reduce the number of functions that a programmer can call to delete some memory. Have one version of FREE and one version of DELETE (or SDK_FREE and SDK_DELETE to make the distinction obvious) that hooks into your memory manager, making NULL a no-op and making the pointer in question a NULL pointer when it’s done. Reducing the number of available functions makes even more sense if the function is actually a macro, as with no scoping available, polluting the namespace is something you really want to avoid.

And this isn’t just about FREE or DELETE. Reduce your macros, reduce your function calls and make your code easier to use, easier to understand and easier to test as a result.

C++ can have some interesting behaviour, sometimes expected and sometimes not so. It’s one of the reasons I enjoy using the language (maybe I like punishment) but it’s one of the reasons many people don’t.

One of the often overlooked aspects of C++ is the way classes can be easily, and incorrectly, copied without you knowing about it, due to the way classes will have copy and creation methods automatically generated for you if you don’t specify them yourself.

This post intends to look at how you can avoid this by making sure you are explicit when creating your C++ classes, through the use of copy constructors and assignment operators. To look at how these can be used, I’ll go through a possibly contrived example, which will show exactly where these members come into play and how not knowing how they work can generate behaviour you don’t expect, or don’t want.

A Vector Implementation
To show how and when these C++ features can be a help or a hindrance I’m going to use a simple example, creating an implementation of a basic vector container. While you might not do this yourself, it will easily show how we can use various member functions to make the object behave exactly how we want it to.

So to start with the basics, this is what our implementation of a vector (and probably most of you basic classes) looks like – and for the sake of simplicity, it won’t be getting more complicated either.

class MyVector
{
public:
  MyVector();
  ~MyVector();

private:
  int       m_entryCount;
  void*     m_entries;
};

So we have the most basic implementation here, a pointer to the vector elements which references dynamic heap memory (this is the member that’s going to be causing us problems) and an integer indicating how many elements the vector currently contains.

As the implementation continues, the vector gains member functions to add elements, return references to them, remove them, increase or decrease the capacity and so on.

Copying The Vector
But as people continue to use the container, they become more comfortable with them until eventually they do the following

MyVector masterVector;
MyVector localCopy;

// ... Add plenty of things to masterVector

// Copy a vector into our local copy so we
// have something to play with
localCopy = masterVector;

This all seems innocent enough – we are copying the one vector into another so we can use the contents and, we assume, modify them without affecting the original. After all, this is how built in types work.

But because our basic vector implementation hasn’t defined an assignment operator it’s not going to do what we expect.

But if we haven’t defined one, surely the compiler will generate a couple of errors because it doesn’t know what to do? Unfortunately in this case, the compiler tries to help you out, by creating a default assignment operator, which does nothing more than a shallow copy. And all a shallow copy does is copy the basic types, nothing more, nothing less.

In effect it does nothing more the following…

localCopy.m_entryCount = masterVector.m_entryCount;
localCopy.m_entries = masterVector.m_entries;

So when we do this, we end up with both m_entries pointers pointing to the exact same area of memory. And this is not a good thing. Especially if the user continues and does the following…

// Copy the vector into a local copy
// so we can alter it
localCopy = masterVector;

// Since the user would assume that
// they have an independent vector,
// they do what they want with it

// Lets clear the contents - which deletes
// all the allocated memory
localCopy.clear();

Since we have two objects pointing to the same area of memory, and one of them just called ‘delete’ on it, we are left in a very bad state. The master vector now references invalid memory and it thinks it actually contains elements, because its m_entryCount hasn’t been effected by the change to the copied vector…

So while in some cases it’s handy for an assignment operator to be automatically generated, in this case it certainly isn’t. And we should make sure that an assignment operator is only ever generated when we explicitly require it.

So the first thing to do is to actually generate an error when someone tries to use ‘=’ unless we specifically request it. And the way to do this is through a private declaration as part of the class.

So we end up with the following

class MyVector
{
public:
  MyVector();
  ~MyVector();

private:
  // Declare a private operator= so nobody can use it
  MyVector& operator= (const MyVector& rhs);
};

By putting the operator= method into the private part of the class, and not defining it, we stop anyone from using it, with the compiler generating an easy to understand and quick error.

Obviously in this case people want to be able to copy one vector to another, but now we have the ability to control how and when this happens. By simply moving the operator= method into the public space, and defining the function so it does a deep copy (in other words it copies the content of the allocated memory rather than just the pointer to the memory) we can properly copy one vector into another.

Users can now copy vectors at will, knowing that each one is independent of the one that came before it and if you don’t want them to, we can easily block them and let the compiler tell them the bad news.

Creating Copies
So we can now control what happens with the vector when someone tries to copy it, but what happens in the following situation?

// Function that takes a vector of objects
void DoSomethingCool(MyVector listOfObjects)
{
  // ... Do some stuff with listOfObjects
  // ... Again, lets clear it
  listOfObjects.clear();
}

// Create our vector
MyVector objectList;

// ... Add plenty of objects to it

// Then pass it along
DoSomethingCool(objectList);

Now this might be a simple mistake. We might have wanted to pass by reference rather than value, but that’s irrelevant. By passing by value we have forced the compiler to automatically generate a copy constructor. And this comes with all the problems we had with an automatically generated assignment operator. Especially as the local function goes and clears the vector again…

So we have the exact same solution to the copy constructor problem as we had with the assignment operator…

class MyVector
{
public:
  MyVector();
  ~MyVector();

private:
  // Declare a private copy constructor so nobody can use it
  MyVector(const MyVector& rhs);
  MyVector& operator= (const MyVector& rhs);
};

So again we can make the pass by value safe by either blocking the creation by keeping it private or by moving the copy constructor into the public space and defining a deep copy, making sure that again our vectors are independent.

You can also use the copy constructor to generate new objects at the point of creation, by calling the copy constructor explicitly.

MyVector masterVector;
// Add stuff to the master vector

// Create a new one using the original
MyVector copiedVector(masterVector);

By using the copy constructor explicitly, you may be able to reduce a more expensive call to the default constructor followed by an assignment operator into a single, more efficient call.

Creation or Assignment?
The following might not do what you think it does

MyVector masterVector;
// Add stuff to the master vector

// Create a new one using the original
MyVector copiedVector = masterVector;

Does this call the assignment operator, or the copy constructor, or something else?!?

It’s using the ‘=’ operator, but the important part of the question is that we using this as the point of creation, so we, maybe surprisingly, use the copy constructor in this case.  I’ll look at ways that assignment/creation operations can be made more explicit in a later post.

This is worth remembering as calling the default constructor followed by the assignment operator might be more expensive than simply calling the copy constructor.

Summary

  • The assignment operator and copy constructor are used at different times of an objects lifecycle.
  • MyVector createdVector1(masterVector);  // Uses the copy constructor
    MyVector createdVector2 = masterVector;  // Uses the copy constructor
    createdVector1 = createdVector2; // Uses the assignment operator
  • If you need an assignment operator, or a copy constructor, then you will more than likely need the other. Even if you think you might not, you need to make your class safe for the end user, so adding them both it the best way forward.
  • You should create a private copy constructor and assignment operator by default, only removing them when you need a shallow copy, or defining them if they want a deep copy. So by default all your classes should start life looking like the following (you’re more likely to forget to add them when you don’t need them, than remove them if you do)
  • class DefaultClass
    {
    public:
      DefaultClass();
      ~DefaultClass();
    
    private:
      // Declare private copy constructor and assignment operator,
      // only removing them when we actually need them...
      DefaultClass(const DefaultClass& rhs);
      DefaultClass& operator= (const DefaultClass& rhs);
    };
  • If you only need a shallow copy, then you can remove the private declarations since the compiler can do all the work for you. But only remove them if you explicitly want the objects to be copied.
  • All this relates to structures as well as classes.  But if you are looking at assignment operators and copy constructors for one of your structs, you might be better off creating a class rather than a struct.

The information here only scrapes the surface of how to best use assignment operators and copy constructors, but you can easily investigate how to use these and other automatically generated functions to make your objects more efficient and, most importantly, safe for the users.  Without knowing how and when these class members are used, and how to take advantage of them, you can’t confidently say that the objects you are creating are safe to use in the situations they will be used in.

I’m going to look at a couple of other well hidden features of C++ in future post which will compliment the use of assignment operators and copy constructors quite nicely.


Everybody who has had even a cursory glance at game degrees, whether they are technical, artistic or design based, knows that they come in for some abuse. You hear what can only be described as horror stories, people who have spent 3 or 4 years of their lives, racked up a large amount of debt, only to come out at the end with a piece of paper that not only doesn’t give them the skills to get into the Games Industry, but doesn’t give them the skills to get into any other kind of industry either.

Fortunately, not all of them are of the same quality, but with the general attitude towards them, its very difficult and daunting to try and find one that is not only worthwhile, but one which will benefit you if you find out the games industry isn’t the right industry for you.

SkillSet (or the ‘Sector Skills Council for Creative Media’) is a body that (amongst other things) works with Universities to monitor, recommend and guide course content, pushing it in a direction (if it isn’t there already!) that will provide students with the right skills, and experience, to enter the games industry and provide them with the talents to move into other industries if that’s where life takes them.

And it doesn’t work alone.  Working with companies and individuals from the games industry and Universities it can constantly check and discuss what is being suggested, what is needed and how best to get the required skills to those that want them.

Accreditation is one of the main ways in which SkillSet is able to easily and clearly indicate that a University course is, for want of a better phrase, ‘fit for purpose’ and while it can be a hard process to get through it is something that really benefits the Universities in the short and long term.

Accreditation is a process in which Universities apply to SkillSet with a set of documentation that covers, amongst other things, the following.

  • Course Content – Are they teaching what the industry wants.  Advanced C++ and math, team work and development (source control tools, cross discipline development, leadership and teamwork skills) and console development spring to mind
  • Equipment – When joining an industry that uses technology not available in any other industry, it helps if you have already experienced what it’s like developing for them.  Platform holders are happy to work with Universities to provide equipment for their students to use, and they should have good exposure to it.
  • Industry Involvement – Do they have guest speakers or work with companies to form their course content?
  • Outcomes – How many of their students get roles in the industry when they graduate and what roles are they filling?  Are they able to get jobs in other industries if they want to?

The documents that applicants complete are freely available here if you want to have a more detailed look.

Representatives from the Games Industry then take part in the accreditation process, reviewing the application content, and feeding back to SkillSet and the University before, if successful, moving onto a more detailed phase of presentations, visits and interviews.

And it should be stressed that it is these industry representatives, always from a development background, that have the final say.

There are currently courses that are accredited (and I stress courses, as a University who’s Art track is accredited may not have it’s Tech track accredited) and you can easily find out the content of their courses to see why these have been given a big thumbs up from the Industry.  Obviously as the process continues, gets more streamlined and improves, more courses will be added to this list, hopefully sometime this year and on a yearly basis after that…

I was originally going to end this post with a ‘what to look for’ and a ‘what to avoid’ paragraph for future students, but I want this to be about the work that SkillSet is doing, and how their process is not only useful, but is driven by the industry that is being fed into.  There will always be discussions as to how to improve the process and it’s encouraging to see how many companies and individuals take part in these talks (on both the University and Industry side).

So if you are looking at going on a ‘Game Degree’ in the near future, make sure you check out the current list of accredited courses, and if you can’t get to one of those, examine the course content in detail to see how it compares or to see if they are in the process of being accredited.  If you still can’t find the information you need, request more information from the University.  They benefit from you being there to, so it needs to be a two way street before you even think of enrolling.

Thoughts?

Last night I tried to update various blog plug-ins and I decided to do it while watching a rather good episode of House. Lets just say I shouldn’t have been distracted.

So if any RSS feeds have been spammed as I tried to fix the general mess that the half updated and broken installs created, then I apologise.

As an aside, I took this opportunity to update my Blog Roll with a subsection of the blogs I regularly read (if I put all of them it would be to long a list) so have a look through and see if there’s anything you haven’t seen before and get subscribed! If I’m missing anything, or there are blogs that should be there, let me know.

Normal service will now resume.

I’m not one for bringing up promotions from companies but it was brought to my attention the other day that SmartBear are offering 5 licences for their Code Reviewer tool (a more light weight version of Code Collaborator) for the tiny sum of $5. And in the way that marketing departments like things to flow together, they are only doing this for 5 days – from July 13th to 17th. 5 licences for $5, only for 5 days.

I’m a fan of SmartBear’s tools, I’d go as far as to say that Code Collaborator is one of my favourite code review tool out there, but to be honest what makes me want to mention this is that they will donate all the money raised from this promotion to a start-up to help them keep their heads above water (as of writing this it’s not been announced which one).

They are also providing a mid-week Webinar that will step you through how to use Code Reviewer, so check that out if you need a bit more information about it.

Anyway, if this might persuade you to give code reviewing a go or could help you formalise you process a little bit more, then check it out and see if this is right for you.