The general idea is:
You variable has to stay in scope. If you create a variable in a function it will stop to exist when then the function ends. This is only true if you put the variable on stack instead of the heap. All variables are on the stack, the only exceptions are variables which are created with new, static or global variables. So if you don't use new and a pointer the content of your variable will be lost. Example:
char* readName()
{
char name[64];
scanf("%s", name);
return name;
}
int main()
{
char* name = readName();
std::cout << name << std::endl;
}
You will get:
g++ po.c -o po
po.c: In function ‘char* readName()’:
po.c:7:10: warning: address of local variable ‘name’ returned [-Wreturn-local-addr]
char name[64];
^
./po
Input: xxx
Output: @`
This is not what you want, you get random data because your variable stopped to exist, because it was on the stack. Lets do it with a variable on the heap, so it will not be deleted.
#include <iostream>
#include <stdio.h>
using namespace std;
char* readName()
{
char* name = new char(64);
scanf("%s", name);
return name;
}
int main()
{
char* name = readName();
std::cout << name << std::endl;
delete[] name; //you have to delete heap variables to get the RAM back
}
You see that name is created on the heap. Lets use it.
g++ po.c -o po
./po
Input: xxx
Output: xxx
Wait you used pointer both time you will complain. This is true, because I wanted to show it to you with an array. If a graphics library is using a pointer to video memory , the video memory is an array "on the heap" too. Disclaimer: Not realy the heap but the gpu but it acts like an array on the heap. But don't use free on it!
An other reason is the amount of RAM needed.
struct Level
{
size_t data[1*1024*1024*1024]; //1 gigabyte data
};
Level* getLevelPointer()
{
Level level = new Level();
return level;
}
Level getLevelCopy()
{
Level level;
return level;
}
void main()
{
Level* level = getLevelPointer();
Level level2 = getLevelCopy();
}
As you can see you have to copy 1 Gigabyte instead of 4 to 8 Bytes for the pointer. And if something is hard to copy, it is sometimes easier to just give a pointer.
You can avoid this problem by using a wrapper class.
struct Level
{
size_t data[1*1024*1024*1024]; //1 gigabyte data
};
class LevelWrapper
{
Level level;
LevelWrapper() : level()
{
}
inline Level& getLevel()
{
return level;
}
};
Level* getLevelPointer()
{
Level level = new Level();
return level;
}
Level getLevelCopy()
{
Level level;
return level;
}
void main()
{
Level* level = getLevelPointer(); //level lives on the heap
Level level2 = getLevelCopy(); //level is created on copied to main
LevelWrapper wrapper;
Level& level3 = wrapper.level(); //level lives in wrapper, using a reference to get it
}
If you are using pointers you also don't have confusion with deep copies. If you use pointers you know you share the data. If you use variable copies of the class you think you own the data and can change it without changing the other variable. Here is an example. If I change the name of p2 I will change the name of p1, even if they are copies not pointers. The output is the address of the internal pointer of Person (sorry for C style coding).
#include <stdio.h>
#include <malloc.h>
struct Person
{
int age;
char* name;
};
void main()
{
struct Person p1;
p1.name = (char*) malloc(64*sizeof(char));
p1.name = "Junior";
p1.age = 16;
struct Person p2 = p1;
printf("%p %p \n", p1.name, p2.name);
}
./pers
0x400624 0x400624
Btw. use shared pointer instead of normale pointer. They are sometimes a tiny bit slower, but you don't have to clean them up with delete (which you can sometimes forget).
std::shared_ptr<MyObject> MyObjectPtr(new MyObject("Strawberries"));