Вы находитесь на странице: 1из 82

CSE 380 Computer Game Programming C++ Boot Camp

BioShock by 2K Games, 2007

What is memory?
Think of it as a giant array
0xffffffff

Stack Segment

How do we assign data to/get data from memory?


memory addresses these are indices into the memory array
addresses are typically byte addressable
0x10000000

Heap Segment Global Segment

0x00000000

What goes in each memory segment?


Stack Segment Temporary local variables declared inside methods removed from memory when a method returns Stack Segment

Heap Segment for dynamic data (whenever you use new) data for constructed objects (new) persistent as long as an existing object variable references this region of memory
Global Segment data that can be reserved at compile time

Heap Segment
Global Segment

Global Functions & Variables Functions which are not methods of a class
like printf & main on the previous slide

Make sure you dont create a duplicate method signature or duplicate global variables

public class PhoneListing { public int number = 0; public String name = "NONE";//global public PhoneListing() {}

Where is our Java data being stored?

public static void main(String[] args) { test1(); } public static void test1() { PhoneListing test = new PhoneListing(); //heap, 8 bytes Where will test be stored? test.number = 8675309; How much memory test.name = new String("Jenny"); will be reserved? printDetails(test); } public static void printDetails(PhoneListing d)//phonelisting d goes on stack {

System.out.println("Call " + d.name + " at "

How about the following C++ method?


public static void testCPP() { PhoneListing test1;//declare & initialize test1.number = 8675309; // OR WE COULD DO PhoneListing *test2 = new PhoneListing(); test2->number = 8675309; (*test2).number = 8675309; }

There is a major difference here, what is it?

Why do we care about this?


This is important to understand proper data manipulation Be careful where you put your data! Data put on the stack disappears when the method returns! Were going to see an example error a bit later

Game Programmers Cycle


Games are heavily reliant on performance

Traditional game developer expectations:


plan to throw out code every couple of games and start anew (every 2-3 years) less reliant on legacy code under more pressure than most developers to develop complex products quickly with small teams

Language Shifts
Game developers should continually look to take advantage of the latest advances (including changing languages)
language shifts approximately every 10 years the truth is most programmers use one language for most of their career. Why?
either they dont want to, or their employer doesnt want to

Why are we here?



To prevent C & C++ from becoming the obstacle to learning to build game technologies What will we cover?
Text Arrays & structs Pointers Call by Value vs Call by Reference Objects & classes Inheritance

Some reasons why C++ can be painful


No single standard Many compilers named different things They each have their own ways of doing things In Visual Studio, youll make 2 types of source files:
.h : header files .cpp : c++ source files

Where do we start?
Hello World of course 1. Start Visual C++ 2. Select: New Project Visual C++ Win32 Project 3. Name your project HelloWorld 4. Place it on your desktop 5. Click OK and then Finish buttons

What do we get? a mess, try running it welcome to the world of Windows programming

Change HelloWorld.cpp to the following


#include "stdafx.h" wchar_t dialogText[25];

int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { dialogText[0] = '\0'; wcscat(dialogText, L"Hello"); wcscat(dialogText, L"\nWorld!");
wchar_t dialogTitle[25]; dialogTitle[0] = '\0'; wcscat(dialogTitle, L"Wide Characters"); MessageBox(NULL, dialogText, dialogTitle, MB_OK);

MessageBox method
From Windows library Similar to JOptionPane in Java, but no text input Many customizable dialog types
set type
http://msdn2.microsoft.com/en-us/library/ms645505.aspx

Ex, to get button selection from user, add the code on the following page to HelloWorld BTW, well never use this again

Whats a wchar_t?
A C++ type

It stores wide characters Why not use char?


might not accommodate Unicode in truth, windows uses wchar_t
they have their own similar type WCHAR

so well use wchar_t for all text

And for strings of text?


Well use arrays of wchar_t How? 1. Create the array with a max capacity 2. Make the first character '\0', the NULL character 3. Use C library functions to build & manipulate
wchar_t dialogTitle[25];

dialogTitle[0] = '\0'; wcscat(dialogTitle, L"Wide Characters");

C methods for wchar_t text


http://opengroup.org/onlinepubs/007908799/xsh/wchar.h.html

Some useful ones:


wcscat: concatenate wcscmp: for comparing text wcscpy: for copying text wcslen: length of string wcstod: text to double wcstok: tokenize wcstol: text to long etc.

Also some Windows methods: _itow: int to wchar_t array _wtoi: wchar_t array to int _wtof: wchar_t array to float

Text Exercise
Make a program that does the following:

1. Selects a random int from 1 to 100 2. Loads the int into a wchar_t array 3. Displays the text in a MessageBox

Then, do the same thing with a float instead of an int

How do you generate random ints?


First you have to seed a random number generator:
Ex: srand(GetTickCount());

Now, use rand() to get a random number


you can % it to limit the range you can add to it to shift the range

For example, for a random number 100 200: int num = (rand() % 101) + 100;

Arrays
Weve used them already

In C++, you can put an array on the stack, global region, or the heap
which ones have we done so far?
global (dialogText) the stack (dialogTitle)

Exercise
Change your program such that all array data goes on the heap Note: data goes on the heap when you call new new: constructs an object/array and returns a memory address (pointer) to that location
just like in Java

Lets try to create a memory leak


Make a new Win32 Console project with the following:
#include "stdafx.h" #include <iostream> using namespace std; #include "MemoryLeakTest.h" int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { wchar_t text[25]; int counter = 1; while (counter < 10000) { Sleep(1000); _itow(counter, text, 10); cout << text << endl; counter++; } }

Run the program Also, open the task manager (CTRL ALT DEL) Is there a memory leak?

How about now?


Change the code to:
wchar_t *text; int counter = 1;
while (counter < 10000) { text = new wchar_t[1000]; Sleep(1000); _itow(counter, text, 10); cout << text << endl; counter++; }
Whats happening?

Ever used C?
Java inherited much from C
similar primitives (not entirely the same) similar conditional statements similar loops

But lots is different


pointers structs C memory management and much more

What is a computers memory?


A sequential group of storage cells
typically a cell is a byte

Each cell has an address (a number) In C as in Java


some cells contain data some cells contain references to other memory addresses memory addresses are typically 4 bytes

Pointers
In Java, what do object variables store?
memory addresses this makes them pointers what do they point to?
object data on the heap

In C, you can have either:


a pointer to a struct/array/primitive OR the actual struct/array/primitive

*
* is a C operator used for 2 purposes:
1. To declare a variable as a pointer. Ex:
int *myIntPointer; right now, myIntPointer points to a random address trying to use before initialization results in a segmentation fault or bus error

2. To dereference an existing pointer variable. Huh?


means to get whats at the address the pointer stores

&
A C operator used for getting the address of a variable

This would produce an address similar to whats stored by a pointer

Think of it this way


When you compile a C program, instructions are added for properly running your program One thing these instructions do is manipulate declared variables Every declared variable is stored at a memory location So the question is whats there?
for a regular int, just a number for an int*, a memory address of an int

Example, what output will we get?


int num = 5; int *pNum = &num; num = 7; printf("num = %d\npNum = %d\n", num, *pNum); if (&num == pNum) else printf("true\n"); printf("false\n");

OUTPUT: num = 7 pNum = 7 true

So who cares? Why do we need pointers? What good are they?

In C, pointers can be used to multiple advantages:


call-by-reference methods dynamic arrays dynamic memory allocation using pointer arithmetic

Data at the end of a pointer can be filled in later

Call-by-value
In Java, when you pass an argument to a method, you are actually passing a copy of that argument
this is called call-by-value

Ex:
public static void main(String[] args) { int x = 5; junk(x); System.out.println("x is " + x); } public void junk(int argument) { argument++; }

OUTPUT: x is 5

C also has call-by-reference


We can pass the adddress of a variable. So?
We can directly change the original variable

Ex:
void junk(int cbv, int *cbr); OUTPUT: int main() x is 5 { int x = 5; y is 7 int y = 6; junk(x, &y); printf("x is %d\ny is %d\n", x, y); } void junk(int cbv, int *cbr) { cbv++; (*cbr)++;

Is it still call by value?


Some might say its still technically call-by-value
we are passing a copy of the address

So, assigning an address to the pointer would not change the original pointer

Whats the output and why?


void junk(int *test); int main() { int x = 5; junk(&x); printf("x is %d\n", x); } void junk(int *test) { int num = 10; test = &num; }

OUTPUT: x is 5

Whats dynamic memory allocation?


In Java when objects are constructed based on decisions made at runtime In C, when structs and arrays are constructed based on decisions made at runtime For dynamic structs & arrays, we can use pointers

First things first, whats a struct?


Like a record in Pascal

A single construct that can store multiple variables


sounds like an object BUT does not have methods

Declaring a struct type & struct variables


To declare a struct type: struct Point { int x; int y; }; To declare a struct variable: struct Point p1; To reference data in a struct, use . operator, just like an object: p1.x = 5;

struct Point { int x; int y; }; void changePoint(struct Point p); int main() { OUTPUT: struct Point p1; p1.x = 100; p1.x is 100 p1.y = 200; p1.y is 200 changePoint(p1); printf("p1.x is %d\np1.y is %d\n", p1.x, p1.y); } void changePoint(struct Point p) { We just changed p, a p.x *= 5; copy of p1, but not p1 p.y *= 4; }

struct Point { int x; int y; }; void changePoint(struct Point p); int main() { OUTPUT: struct Point p1; p1.x = 100; p1.x is 500 p1.y = 200; p1.y is 800 changePoint(&p1); printf("p1.x is %d\np1.y is %d\n", p1.x, p1.y); } void changePoint(struct Point *p) { We just changed p, and (*p).x *= 5; so changed p1 (*p).y *= 4; }

BTW, where is p1 in memory?


int main() { struct Point p1; IN THE main method STACK FRAME! p1.x = 100; p1.y = 200; changePoint(&p1); printf("p1.x is %d\np1.y is %d\n", p1.x, p1.y); }

struct Point { int x; int y; }; void changePoint(struct Point p); int main() { struct Point *p1 = makePoint(); printf("p1.x is %d\np1.y is %d\n", (*p1).x, (*p1).y); } struct Point* makePoint() What happens? { struct Point p1; p1.x = 100; DISASTER! WHY? p2.y = 200; return &p1; } When makePoint ends, p1

gets popped from the stack

How can we fix this? Declare a struct pointer variable

When you want to make one on the heap, use malloc


Whats malloc?
a method for dynamic memory allocation you give it a size it gives you that many bytes of continuous memory cells it returns you the address of the first byte in the block

Note, always free what you malloc


C has no garbage collector If you malloc something, when youre done with it you need to free it Why?
if you dont the memory will not be recycled this is called a memory leak

Who cares?
you should if you want your program to run efficiently

Whats free?
a method that releases the memory block argument

struct Point { int x; NOW IT WORKS int y; }; void changePoint(struct Point p); int main() { struct Point *p1 = makePoint(); printf("p1.x is %d\np1.y is %d\n", p1->x, p1->y); } struct Point* makePoint() { struct Point *p1; p1 = malloc(sizeof(struct Point)); (*p1).x = 100; (*p2).y = 200; return p1; }

->
Used to dereference data in a pointer to a struct or array. Ex:
struct Point { int x; int y; }; int main() { int pointBytes = sizeof(struct Point); struct Point *p = malloc(pointBytes); p->x = 10; p->y = 20; printf("x is %d\ny is %d\n", p->x, p->y); free(p); }

What if we dont free?


struct Point *p; int pointSize = sizeof(struct Point); int i; for (i = 0; i < 10000; i++) { p = malloc(pointSize); p->x = i % 1000; p->y = i % 500; printf("p->x is %d\tp->y is %d\n", p->x, p->y); }

Memory Leak! (thats a bad thing) - note, by the time this loop ends, your program will be using up 8 bytes * 10000 = 80000 bytes of memory for one p variable - whered I get 8 bytes from?

What if we dont free?


struct Point *p; int pointSize = sizeof(struct Point); int i; for (i = 0; i < 10000; i++) { p = malloc(pointSize); p->x = i % 1000; p->y = i % 500; printf("p->x is %d\tp->y is %d\n", p->x, p->y); free(p); } No memory leak now What if we were to use p->x now? dangling reference (thats bad) it might still be there, it might not (segmentation fault error possible)

We can dynamically construct arrays too


With malloc, we can request continuous blocks of memory right? So a * will point to the front of the block That can be the first index in an array What can we put into arrays?
primitives pointers to primitives (other arrays of primitives) structs pointers to structs

char* as an array
char *text; text = malloc(sizeof(char) * 4); int i; for (i = 0; i < 3; i++) text[i] = (char)(65 + i); text[3] = '\0'; printf("text is %s\n", text);
Output: text is ABC

Pointers to Pointers (for 2D arrays)


char **text2; text2 = malloc(sizeof(char*) * 2);

text2[0] = malloc(sizeof(char) * 4); for(i = 0; i < 3; i++) text2[0][i] = (char)(i + 65); text2[0][3] = '\0'; printf("text2[0] is %s\n", text2[0]);
text2[1] = malloc(sizeof(char) * 6); for(i = 0; i < 5; i++) text2[1][i] = (char)(i + 68); text2[0][5] = '\0'; printf("text2[1] is %s\n", text2[1]);

Array of structs
struct Point *points; int numPoints = 5; points = malloc(sizeof(struct Point) * numPoints); int i; bash-2.05$ ./StructArraysTester srand(time(NULL)); points[0] = (597,209) for (i = 0; i < numPoints; i++) points[1] = (41,800) { points[2] = (464,96) points[3] = (59,892) points[i].x = rand() % 1000; points[4] = (418,231) points[i].y = rand() % 1000; printf("points[%d] = (%d,%d)\n", i, points[i].x, points[i].y); }

Array of struct pointers


struct Point **array; int numPointers = 100; int numPoints = 0; array = malloc(sizeof(struct Point*) * numPointers); srand(time(NULL)); OUTPUT: int i; point0 = (403,358) for (i = 0; i < 2; i++) point1 = (941,453) { array[i] = malloc(sizeof(struct Point)); array[i]->x = rand() % 1000; array[i]->y = rand() % 1000; numPoints++; printf("point%d = (%d,%d)\n", i, array[i]->x, array[i]->y); }

Segmentation Fault
One of the most common C errors

Means you are trying to access a place in memory that you do not have permission to access
Typical problems:
accessing uninitialized pointer improper pointer arithmetic

Detecting Memory Leaks


How do we know if we have a memory leak? Is the programs memory footprint growing when it should not be?
If yes, you have a leak

malloc gets passed the # of bites to allocate free does not get passed such info
this info exists in library methods, but we dont have access to it

To track memory allocation, we can define our own memory allocation/deallocation methods

What are our malloc & free going to do?


Same as before. How?
well call Cs malloc and free from them

What else?
when mallocing, add a little extra memory for some header info when freeing, extract header info what kind of info?
size of allocation checksum for error checking

Time to practice pointer arithmetic


Whats that? Feature of C language If you have a pointer char *text, it points to memory address storing text text + 1 points to 1 byte after start of text
might be second character might not you need to know what youre moving your pointer to

Why do we care?
we need to stick our info at the front of our object

malloc_info
Our header
well stick in in front of each piece of data we allocate
We can total memory usage in global variables totalAlloc, totalFreed, dataAlloc, & dataFreed
#define MALLOC_CHECKSUM 123456789 struct malloc_info { int checksum; size_t bytes; }; long totalAlloc, totalFreed, dataAlloc, dataFreed;

void* our_malloc(size_t bytes) { void *data; struct malloc_info *info; data = malloc(bytes + sizeof(struct malloc_info)); if (!data) return NULL; else { size_t headerSize = sizeof(struct malloc_info); totalAlloc += bytes + headerSize; dataAlloc += bytes; info = (struct malloc_info *)data; info->checksum = MALLOC_CHECKSUM; info->bytes = bytes; char *data_char = (char*)data; data_char += headerSize; return (void*)data_char; } }

void our_free(void *data) { struct malloc_info *info; void *data_n_header; size_t header_size = sizeof(struct malloc_info); char *data_char = (char*)data; data_char = data_char - header_size; data_n_header = (void*)data_char; info = (struct malloc_info *)data_n_header; if (info->checksum != MALLOC_CHECKSUM) throw std::bad_alloc(); totalFreed += info->bytes + sizeof(struct malloc_info); dataFreed += info->bytes; free(data_n_header); }

So what?
So we can monitor the following differences:
totalAlloctotalFreed dataAllocdataFreed

We can also reset them if we wish Why?


reset before a method starts check differences after method completes
only relevant for methods that are supposed to have a 0 net memory allocation

if differences > 0, memory leak may exist

C++ Objects Split into two files


header files (.h): contains class declarations for one or more classes program files (.c, .cpp): contain method definitions

For example, if we wanted a Hello class:


Hello.h Hello.cpp

Hello.h // declare a class Hello class Hello { public: // begin the public section Hello(); // declare a constructor private: // begin the private section int num; // declare an instance variable }; Hello.cpp #include Hello.H" Hello::Hello() // definition of Hello constructor { num = 5; // the constructor initializes num }

:: Used for scoping methods


specifies what class a method belongs to

So, in Hello.cpp, we might add:


int Hello::myMethod(int a, int b) { return a+b; }

We should then add the method header to the Hello.h file

Inlining methods Method definitions may be placed inside header files (.h) Huh? When done, these methods are inlined
Whats that?

Whats the benefit?


eliminate overhead of calling a method

Only for small, simple methods


like accessors & mutators

Pointers
In Java, what do object variables store?
memory addresses this makes them pointers what do they point to?
object data on the heap

In C++, you can have either:


a pointer to an object/struct/array/primitive OR the actual object/struct/array/primitive

Danger: compilation error


Make 2 classes:
Class A Class B

Have Class A have an instance variable of type Class B Have Class B have an instance variable of type Class A Whats the problem?

Virtual Functions In Java, all method are virtual (results in a bit of overhead)
allows for methods to be overridden in a child class

What does virtual mean?


which object method to use is determined at runtime by the VM via the rules of polymorphism

In C++, methods are not virtual by default


to allow overriding methods, specify them as virtual

Purely Virtual Methods Like abstract methods in Java Require a child class to override a method Method does nothing on its own To specify, add = 0 after the parameter list in a function declaration Ex:
class Foo { public: virtual int abstractMethod() = 0; };

Memory Management Java uses automatic garbage collection & memory management Convenient for the programmer Slow for performance C++ allows for memory management via:
Pointers Constructors & destructors Allocation & de-allocation of memory

Pointers
Stores the memory address of a variable Denoted by *
tells the compiler we want it to be a pointer when we declare it

Ex:
int* myIntPointer;

Right now, myIntPointer points to a random address


trying to use before initialization results in a segmentation fault or bus error

How can we initialize it?


give it the address of some int variable How do we get that?
&

Using Pointers example For declared variables:


& means address of * means value of (dereference pointer)
returns a copy of the value at that address

So, whats the output?

int* myIntegerPointer; int myInteger = 1000; myIntegerPointer = &myInteger; printf("myIntegerPointer = %d\n", myIntegerPointer); printf("myIntegerPointer = %d\n", *myIntegerPointer);

Output: -268437168 1000

Example using dereferencing What output would result?


int myInteger = 1000; int *myIntegerPointer = &myInteger; printf("%d\n", myInteger); Output: *myIntegerPointer += 5; printf("%d\n", myInteger); } 1000

1005

Pointers to Pointers Use ** Ex:


int myInteger = 1000; int* myIntegerPointer = &myInteger; int** myIntegerPointerPointer = &myIntegerPointer;

Now, *myIntegerPointerPointer Yes, this can get confusing

== myIntegerPointer

Why do we care about pointers? Declaring and assigning objects Object constructors return addresses Correct C++ syntax to declare and assign a Foo object pointer:
Foo* myFooInstance = new Foo(0, 0); OR, for just the object: Foo myFooInstance(0, 0);

To declare/call default constructor:


Foo myFooInstance;

NOTE, this is not NULL

What if we dont the object constructed when declared?

Declare and use a pointer to n object Like weve seen:


Foo* myFooInstance; // points to garbage // NOW CONSTRUCT myFooInstance = new Foo(0, 0);

Using objects I can declare an object and use the . operator to call methods: Foo myInstance; myInstance.someMethod(); NOTE: the same is not true for object pointers

-> does two things for you:


dereferences an object pointer calls a method on the instance or accesses a member variable of the dereferenced object
Foo* myFooInstance = new Foo(0, 0); // now we can use methods via -> myFooInstance->someMethodInFoo(); // OR (*myFooInstance).someMethodInFoo();

Freeing up memory Java has a garbage collector It looks for all the constructed objects you dont need anymore
frees up that memory

In C++, you must collect your object garbage What if you dont?
memory leak in a game, it will kill performance

How?
use delete keyword on object pointers

Delete Use only on global variables and/or object pointers Ex:

Foo * f; // to free the memory pointed to by f: delete f;

Good rules of thumb: 1. memory allocated in a function should be deallocated before it exits 2. memory allocated in a constructor should be deallocated in a destructor

Class Destructors Executed when an instance of a class is destroyed For Foo class, would be ~Foo() What should it do?
delete all object instance variables

Ex:
class Foo { private: Bar* m_barPtr; public: Foo() { m_barPtr = new Bar; } ~Foo() { delete m_barPtr; }

Exercise
Define a class that represents an Employee name, id number ,salary, accessors/mutators Define another class that represents a Payroll has an array of Employees, methods for adding and calculating total payroll salary How many? It might get bigger Write a small program that constructs a Payroll and loads it with 5 Employees, making 20,000, 30,000, 40,000, 50,000, and 60,000 Have your program calculate and then display the Payrolls total salary in a MessageBox

Вам также может понравиться