Book Image

C++ Game Development Cookbook

By : Druhin Mukherjee
Book Image

C++ Game Development Cookbook

By: Druhin Mukherjee

Overview of this book

<p>C++ is one of the preferred languages for game development as it supports a variety of coding styles that provides low-level access to the system. C++ is still used as a preferred game programming language by many as it gives game programmers control of the entire architecture, including memory patterns and usage. However, there is little information available on how to harness the advanced features of C++ to build robust games.</p> <p>This book will teach you techniques to develop logic and game code using C++. The primary goal of this book is to teach you to create high-quality games using C++ game programming scripts and techniques, regardless of the library or game engine you use. It will show you how to make use of the object-oriented capabilities of C++ so you can write well-structured and powerful games of any genre. The book also explores important areas such as physics programming and audio programming, and gives you other useful tips and tricks to improve your code.</p> <p>By the end of this book, you will be competent in game programming using C++, and will be able to develop your own games in C++.</p>
Table of Contents (20 chapters)
C++ Game Development Cookbook
Credits
About the Author
About the Reviewer
www.PacktPub.com
Preface
Index

Managing memory more effectively using dynamic allocation


Programmers generally deal with five areas of memory: global namespace, registers, code space, stack, and the free store. When an array is initialized, the number of elements has to be defined. This leads to lots of memory problems. Most of the time, not all elements that we allocated are used, and sometimes we need more elements. To help overcome this problem, C++ facilitates memory allocation while an .exe file is running by using the free store.

The free store is a large area of memory that can be used to store data, and is sometimes referred to as the heap. We can request some space on the free store, and it will give us an address that we can use to store data. We need to keep that address in a pointer. The free store is not cleaned up until your program ends. It is the programmer's responsibility to free any free store memory used by their program.

The advantage of the free store is that there is no need to preallocate all variables. We can decide at runtime when more memory is needed. The memory is reserved and remains available until it is explicitly freed. If memory is reserved while in a function, it is still available when control returns from that function. This is a much better way of coding than global variables. Only functions that have access to the pointer can access the data stored in memory, and it provides a tightly controlled interface to that data.

Getting ready

For this recipe, you will need a Windows machine with a working copy of Visual Studio.

How to do it…

In this recipe, we will see how easy it is to use dynamic allocation. In games, most of the memory is allocated dynamically at runtime as we are never sure how much memory we should assign. Assigning an arbitrary amount of memory may result in less memory or memory wastage:

  1. Open Visual Studio.

  2. Create a new C++ project.

  3. Add a source file called main.cpp or anything that you want to name the source file.

  4. Add the following lines of code:

    #include <iostream>
    #include <conio.h>
    #include <string>
    
    using namespace std;
    
    int main()
    {
    
      int iNumberofGuns, iCounter;
      string * sNameOfGuns;
      cout << "How many guns would you like to purchase? ";
      cin >> iNumberofGuns;
      sNameOfGuns = new string[iNumberofGuns];
      if (sNameOfGuns == nullptr)
        cout << "Error: memory could not be allocated";
      else
      {
        for (iCounter = 0; iCounter<iNumberofGuns; iCounter++)
        {
          cout << "Enter name of the gun: ";
          cin >> sNameOfGuns[iCounter];
        }
        cout << "You have purchased: ";
        for (iCounter = 0; iCounter<iNumberofGuns; iCounter++)
          cout << sNameOfGuns[iCounter] << ", ";
        delete[] sNameOfGuns;
      }
    
      _getch();
      return 0;
    }

How it works…

You can allocate memory to the free store using the new keyword; new is followed by the type of the variable you want to allocate. This allows the compiler to know how much memory will need to be allocated. In our example, we have used string. The new keyword returns a memory address. This memory address is assigned to a pointer, sNameOfGuns. We must assign the address to a pointer, otherwise the address will be lost. The format for using the new operator is datatype * pointer = new datatype. So in our example, we have used sNameOfGuns = new string[iNumberofGuns]. If the new allocation fails, it will return a null pointer. We should always check whether the pointer allocation has been successful; otherwise we will try to access a part of the memory that has not been allocated and we may get an error from the compiler, as shown in the following screenshot, and your application will crash:

When you are finished with the memory, you must call delete on the pointer. Delete returns the memory to the free store. Remember that the pointer is a local variable. Where the function that the pointer is declared in goes out of scope, the memory on the free store is not automatically deallocated. The main difference between static and dynamic memory is that the creation/deletion of static memory is handled automatically, whereas dynamic memory must be created and destroyed by the programmer.

The delete[] operator signals to the compiler that it needs to free an array. If you leave the brackets off, only the first element in the array will be deleted. This will create a memory leak. Memory leaks are really bad as it means there are memory spaces that have not been deallocated. Remember, memory is a finite space, so eventually you are going to run into trouble.

When we use delete[], how does the compiler know that it has to free n number of strings from the memory? The runtime system stores the number of items somewhere it can be retrieved only if you know the pointer sNameOfGuns. There are two popular techniques that do this. Both of these are used by commercial compilers, both have tradeoffs, and neither are perfect:

  • Technique 1:

    Over-allocate the array and put the number of items just to the left of the first element. This is the faster of the two techniques, but is more sensitive to the problem of the programmer saying delete sNameOfGuns, instead of delete[] sNameOfGuns.

  • Technique 2:

    Use an associative array with the pointer as a key and the number of items as the value. This is the slower of the two techniques, but is less sensitive to the problem of the programmer saying delete sNameOfGuns, instead of delete[] sNameOfGuns.

There's more…

We can also use a tool called VLD to check for memory leaks.

Note

Download VLD from https://vld.codeplex.com/.

After the setup has downloaded, install VLD on your system. This may or may not set up the VC++ directories correctly. If it doesn't, do it manually by right-clicking on the project page and adding the directory of VLD to the field called Include Directories, as shown in the following figure:

After setting up the directories, add the header file <vld.h> in your source file. After you execute your application and exit it, your output window will now show whether there are any memory leaks in your application.

Understanding the error messages

When using the debug build, you may notice the following values in memory during debugging:

  • 0xCCCCCCCC: This refers to values being allocated on the stack, but not yet initialized.

  • 0xCDCDCDCD: This means memory has been allocated in the heap, but it is not yet initialized (clean memory).

  • 0xDDDDDDDD: This means memory has been released from the heap (dead memory).

  • 0xFEEEFEEE: This refers to values being deallocated from the free store.

  • 0xFDFDFDFD: "No man's land" fences, which are placed at the boundary of heap memory in debug mode. These should never be overwritten, and if they are, it probably means the program is trying to access memory at an index outside of an array's max size.