If I have this two vectors of pointers to MyClass
vector<MyClass*> A;
vector<MyClass*> B;
where A is full and B is empty and I do this operation:
B = A;
Have I to delete the pointers of both vectors or just one?
If I have a dynamic object like this:
MyClass *p = new MyClass;
And this pointer:
MyClass *p2;
If I do this operation:
p2 = p1;
Have I to delete both p and p2 or just one of two?
The pointers are pointing to the same piece of memory, so you only need to delete it once.
You get undefined behaviour if you try to delete an object through a pointer more than once.
A pointer is just(*1) a regular variable containing an unsigned integer value. This value is an address in memory where the pointed-to-value is stored.
In simpler terms, you can think of a pointer as an array index to memory.
byte ram[16 * 1024 * 1024 * 1024]; // 16Gbs of memory.
size_t index = 10000; // indexes the 10,000th byte of ram.
byte* ptr = ram+ 10000; // ptr contains the same actual value as index
ptr = &ram[10000]; // same value again
ptr = ram;
ptr += 10000; // same value again
When you declare the variable as a pointer, you are extending it's contract within the language. Although, underneath, it is still just a regular variable, the language will treat your interactions with it differently because it is aware that you are expecting to use it to reference memory like this.
So, to answer your original question: You need to match every alloc with a single, corresponding delete. This is a concept called "ownership".
char* a = new char[64];
char* b = a;
Both a and b contain the same value, the address of our 64 bytes, but only one of them "owns" the allocation.
That determination is up to the programmer, and is deterministic: Which pointer will last longest? Which will try to use the pointer last?
char* a = new char[64];
if (a != nullptr)
{
char* b = a;
strcpy(b, "hello world");
// <-- end of b's lifetime.
}
std::cout << a << '\n';
If we deleted b at the end of it's lifetime, a would still point to it. The actual underlying memory is untouched, the problem is that the memory could be allocated to someone else in the mean time. (You forget your watch in the drawer of a hotel. If you go back a week after your stay, will your watch still be in the top drawer?)
In the above example, clearly a is more authoritative for the allocation, so we should delete after a has finished using it.
char* a = new char[64];
if (a != nullptr)
{
char* b = a;
strcpy(b, "hello world");
// <-- end of b's lifetime.
}
std::cout << a << '\n';
delete [] a; // we used new [] match with delete []
Pointer management can easily be difficult, and has been causing bugs in C code since C existed.
C++ provides several classes that encapsulate the properties of ownership. std::unique_ptr is a single point of ownership for allocations ideal for when you have a container of pointers.
std::vector<std::unique_ptr<YourClass>> myVector;
myVector.emplace_back(new YourClass));
when this vector goes out of scope, the unique_ptr objects will go out of scope, at which point they will delete their allocations. Problem solved.
There is also std::shared_ptr if you may need the ownership to be dynamic...
std::vector<std::shared_ptr<MailItem>> inbox;
std::set<std::shared_ptr<MailItem>> urgent;
// incoming mail goes into inbox, copied to urgent if its a priority...
for (auto it : inbox)
{
if (it->>IsPriority()) {
urgent.insert(it);
// now there are TWO pointers to the same item.
}
}
In the above case, the user can delete an urgent item from inbox but the item still exists. shared_ptr uses a "reference counter" to know how many pointers own the object. In most cases, this is going to be more complex than you need and unique_ptr will be sufficient.
(*1 There are some platforms where pointers are more than just a single variable but that's kind of advanced and you probably don't need to worry about that until such time as you work on such a platform)
Related
What is the difference between these pointers?
I know that this one is going to be stored on the heap, even though a pointer is only 8 bytes anyways, so the memory is not important for me.
int* aa = new int;
aa = nullptr;
and this one is going to be stored on the stack.
int* bb = nullptr;
They both seem to work the same in my program. Is there any difference apart from memory allocation? I have a feeling that the second one is bad for some reason.
2) Another question which is somewhat related:
Does creating a pointer like that actually take more memory? If we take a look at the first snippet, it creates an int somewhere (4 bytes) and then creates a pointer to it (8 bytes), so is it 12 bytes in total? If yes are they both in the heap then? I can do this, so it means an int exists:
*aa = 20;
Pointers are integers that just indicate a memory position, and a type (so they can only point to variables of that type).
So in your examples, all pointers are stored in the stack (unless they are global variables, but that is another question). What they are pointing to is in the heap, as in the next example.
void foo()
{
int * ptr = new int(42);
// more things...
delete ptr;
}
You can have a pointer pointing into the stack, for example, this way:
void foo()
{
int x = 5;
int * ptr = &x;
// more things...
}
The '&' operator obtains the memory position of the variable x in the example above.
nullptr is the typed equivalent to old NULL. They are a way to initialize a pointer to a known and secure value, meaning that they are not pointing to anything else, and that you can compare whether they are NULL or not.
The program will accept pointers pointing to the stack or the heap: it does not matter.
void addFive(int * x)
{
*x += 5;
}
void foo()
{
int x = 5;
int * ptr1 = &x;
int * ptr2 = new int(42);
addFive( ptr1 );
addFive( ptr2 );
addFive( &x );
printf( "%d\n", *ptr1 );
printf( "%d\n", *ptr2 );
// more things...
delete ptr2;
}
The only difference is that the C runtime will keep structures telling how much memory has been spent in the heap, and therefore storing variables in the heap comes at a cost in performance. On the other hand, the stack is always limited to a fixed amount of memory (relatively small), while the heap is much larger, allowing you to store big arrays, for example.
You could take a look at C-Sim, which simulates memory in C (disclaimer: I wrote it).
Hope this helps.
I just learned pointer and delete pointer in class for C++. I tried this code by my own
# include<iostream>
using namespace std;
int main(){
int num = 10;
int *p = new int;
p = #
cout << *p << endl;
delete p;
cout << num << endl;
return 0;
}
After deleting the pointer p, I cannot print the value of num. But if I delete p at the very end of the program, cout << num << endl; will give me 10. Anyone knows where I did run?
You first leaked a pointer
int *p = new int;
p = # // You just leaked the above int
then illegally deleted something you did not new
delete p; // p points to num, which you did not new
You have already received a couple of good answers that point out the mistake, but I read a deeper misunderstanding of the allocation and deallocation of heap vs stack variables.
I realised this has become a pretty long post, so maybe if people think it is useful I should put it as a community Wiki somewhere. Hopefully it clarifies some of your confusion though.
Stack
The stack is a limited and fixed size storage. Local variables will be created here if you don't specify otherwise, and they will be automatically cleaned up when they are no longer needed. That means you don't have to explicitly allocate them - they will start existing the moment you declare them. Also you don't have to deallocate them - they will die when they fall out of scope, loosely speaking: when you reach the end brace of the block they are defined in.
int main() {
int a; // variable a is born here
a = 3;
a++;
} // a goes out of scope and is destroyed here
Pointers
A pointer is just a variable, but instead of an int which holds a whole number or a bool which holds a true/false value or a double which holds a floating point, a pointer holds a memory address. You can request the address of a stack variable using the address operator &:
{
int a = 3, b = 4;
int* p = &a; // p's value is the address of b, e.g. 0x89f2ec42
p = &b; // p now holds the address of b, e.g. 0x137f3ed0.
p++; // p now points one address space further, e.g. 0x137f3ed4
cout << p; // Prints 0x137f3ed4
} // Variables a, b and p go out of scope and die
Note that you should not assume that a and b are "next to" each other in memory, or that if p has a "used" address as its value then you can also read and write to the address at p + 1.
As you probably know, you can access the value at the address by using the pointer indirection operator, e.g.
int* p = &a; // Assume similar as above
*p = 8;
cout << a; // prints 8
cout << &a << p; // prints the address of a twice.
Note that even though I am using a pointer to point at another variable, I don't need to clean up anything: p is just another name for a, in a sense, and since both p and what it points to are cleaned up automatically there is nothing for me to do here.
Heap
The heap memory is a different kind of memory, which is in theory unlimited in size. You can create variables here, but you need to tell C++ explicitly that you want to do so. The way to do this is by calling the new operator, e.g. new int will create an integer on the heap and return the address. The only way you can do something sensible with the allocated memory, is save the address this gives you. The way you do this, is store it in a pointer:
int* heapPtr = new int;
and now you can use the pointer to access the memory:
*heapPtr = 3;
cout << heapPtr; // Will print the address of the allocated integer
cout << *heapPtr; // Will print the value at the address, i.e. 3
The thing is that variables created on the heap will keep on living, until you say you don't need them anymore. You do that by calling delete on the address you want to delete. E.g. if new gave you 0x12345678 that memory will be yours until you call delete 0x12345678. So before you exit your scope, you need to call
delete heapPtr;
and you will tell your system that the address 0x12345678 is available again for the next code that comes along and needs space on the heap.
Leaking memory
Now there is a danger here, and that is, that you may lose the handle. For example, consider the following:
void f() {
int* p = new int;
}
int main() {
f();
cout << "Uh oh...";
}
The function f creates a new integer on the heap. However, the pointer p in which you store the address is a local variable which is destroyed as soon as f exits. Once you are back in the main function, you suddenly have no idea anymore where the integer you allocated was living, so you have no way to call delete on it anymore. This means that - at least for the duration of your program - you will have memory that according to your operating system is occupied, so you cannot use it for anything else. If you do this too often, you may run out of memory even though you can't access any of it.
This is one of the errors you are making:
int* p = new int;
allocates a new integer on the heap and stores the address in p, but in the next line
p = #
you overwrite that with another address. At this point you lose track of the integer on the heap and you have created a memory leak.
Freeing memory
Aside from freeing memory not often enough (i.e. not instead of once), the other error you can make is freeing it too often. Or, to be more precise, you can make the error of accessing memory after you have told your OS you don't need it anymore. For example, consider the following:
int main() {
int* p = new int;
*p = 10;
delete p; // OK!
*p = 3; // Errr...
}
That last line is very wrong! You have just returned the memory allocated when you called delete, but the address is still stored in p. After you call delete, your OS is allowed to re-allocate the memory at any time - for example, immediately after another thread could call new double and get the same address. At that point, if you write *p = 3 you are therefore writing to memory that is no longer yours which may lead to disaster, if you happen to overwrite the location in memory where the nuke's launch codes are stored, or nothing may happen at all because the memory is never used for anything else before your program ends.
Always release your own memory, and nothing but your own memory
We have concluded the following: memory allocated on the stack is not yours to claim, and not yours to release. Memory allocated on the heap is yours to claim, but you must also release it once and only once.
The following examples are incorrect:
{
int a = 3;
int* p = &a;
delete a;
} // Uh oh... cannot clean up a because it is not ours anymore!
{
int* p = new int;
delete p;
*p = 3; // Uh oh, cannot touch this memory anymore!
delete p; // Uh oh, cannot touch this memory anymore!
}
Why does it print 10?
Well, to be honest, you were just "lucky" there. Actually, the way your operating system manages memory, is generally pretty lazy. When you tell it "I would like some memory" it doesn't zero it for you. That is why it is a bad idea to write
int main() {
int a;
a = a + 3;
cout << a;
}
You get allocated a variable a somewhere in the memory, but the value of a will be whatever was in that memory location. It might be zero, or some random number that depends on how the bits fell when you booted your computer. That is why you should always initialize the variable:
int a = 0;
Similarly, when you say "I don't need this memory" anymore, the OS doesn't zero it. That would be slow and unnecessary: all it needs to do is mark the memory as "free to be re-allocated". So if you give it back and access it immediately afterwards, the probability that it has not been re-allocated yet is pretty large. Therefore
int* p = new int;
*p = 10;
delete p;
cout << *p;
is not guaranteed to print 10. The address p is pointing to may have been (partially) taken (and initialized!) by someone else immediately after the delete. But if it hasn't, the memory will still contain the value 10 there so even though it isn't yours anymore, C++ will still allow you to access it. Basically, when you are using pointers, you are telling it "trust me, I'm a programmer - you don't need to do all kinds of slow checks to make sure I'm staying where I'm supposed to be, instead I'll be careful about that myself!"
using namespace std;
int main(){
int num = 10; // a) an int is created on stack
int *p = new int; // b) another int is allocated on heap
p = # // c) address of int from stack is assigned to p and the pointer
// allocated in b) is leaked: as nothing points to it anymore,
// it can't be deleted
cout << *p << endl;
delete p; // d) deleting a pointer that was not dynamically allocated
// and is pointing to stack.
cout << num << endl;
return 0;
}
What happens when I do something like
int * ptr = new int;
*ptr = 5;
// ... do some stuff here
ptr = new int;
// ... reuse ptr to do some other stuff
as opposed to
int * ptr1 = new int;
*ptr1 = 5;
// ... do some stuff here
delete ptr1;
int * ptr2 = new int;
// ... use ptr2 now
????
Does the same thing happen at the hardware level? In other words, in the first case, does ptr = new int; move on from its previous pointer/value pair, and what happens to those old values? Do they get replaced, do they just float around somewhere, etc.?
Your int *ptr is just a variable that stores an address, nothing more.
After your first int * ptr = new int;, it contains the address to a dynamically allocated integer. After your second int * ptr = new int;, it contains the address to another dynamically allocated integer.
What happens then is nothing special, the only thing is that you didn't call delete so the memory allocated for the first integer will never be freed. There's nothing to keep track of it, its address isn't stored anywhere, and so it will keep being useless allocated space until the program ends.
In the first example, the pointer is overwritten, but the object it pointed to still exists and is "floating around" somewhere. This causes memory leaking.
If this happens in a frequently used function or in a loop, you could easily exhaust your memory, storing values that you can't nor won't access any more.
Leaking is in fact a very common error. A good practice is to avoid it by using smart pointers such as shared_ptr. These keep track of a usage count, and free the object automatically if it's no longer used. For example:
shared_ptr<int> ptr = make_shared<int>(); // allocate an int
*ptr = 5;
// ... do some stuff here
ptr = make_shared<int>(); // the old object is no longer used so deleted automatically
// ... reuse ptr to do some other stuff
A very general question: I was wondering why we use pointer to pointer?
A pointer to pointer will hold the address of a pointer which in turn will point to another pointer. But, this could be achieved even by using a single pointer.
Consider the following example:
{
int number = 10;
int *a = NULL;
a = &number;
int *b = a;
int *pointer1 = NULL;
pointer1 = b; //pointer1 points to the address of number which has value 10
int **pointer2 = NULL;
pointer2 = &b; //pointer2 points to the address of b which in turn points to the address of number which has value 10. Why **pointer2??
return 0;
}
I think you answered your own question, the code is correct, what you commented isn't.
int number = 10; is the value
int *pointer1 = b; points to the address where int number is kept
int **pointer2 = &b; points to the address where address of int number is kept
Do you see the pattern here??
address = * (single indirection)
address of address = ** (double indirection)
The following expressions are true:
*pointer2 == b
**pointer2 == 10
The following is not!
*pointer2 == 10
Pointer to pointer can be useful when you want to change to what a pointer points to outside of a function. For example
void func(int** ptr)
{
*ptr = new int;
**ptr = 1337;
}
int main()
{
int* p = NULL;
func(&p);
std::cout << *p << std::endl; // writes 1337 to console
delete p;
}
A stupid example to show what can be achieved :) With just a pointer this can not be done.
First of all, a pointer doesn't point to a value. It point to a memory location (that is it contains a memory address) which in turn contains a value. So when you write
pointer1 = b;
pointer1 points to the same memory location as b which is the variable number. Now after that is you execute
pointer2 = &b;
Then pointer2 point to the memory location of b which doesn't contains 10 but the address of the variable number
Your assumption is incorrect. pointer2 does not point to the value 10, but to the (address of the) pointer b. Dereferencing pointer2 with the * operator produces an int *, not an int.
You need pointers to pointers for the same reasons you need pointers in the first place: to implement pass-by-reference parameters in function calls, to effect sharing of data between data structures, and so on.
In c such construction made sense, with bigger data structures. The OOP in C, because of lack of possibility to implement methods withing structures, the methods had c++ this parameter passed explicitly. Also some structures were defined by a pointer to one specially selected element, which was held in the scope global to the methods.
So when you wanted to pass whole stucture, E.g. a tree, and needed to change the root, or 1st element of a list, you passes a pointer-to-a-pointer to this special root/head element, so you could change it.
Note: This is c-style implementation using c++ syntax for convienience.
void add_element_to_list(List** list, Data element){
Data new_el = new Data(element); // this would be malloc and struct copy
*list = new_el; //move the address of list, so it begins at new element
}
In c++ there is reference mechanismm and you generally you can implement nearly anything with it. It basically makes usage of pointers at all obsolete it c++, at least in many, many cases. You also design objects and work on them, and everything is hidden under the hood those two.
There was also a nice question lately "Why do we use pointers in c++?" or something like that.
A simple example is an implementation of a matrix (it's an example, it's not the best way to implement matrices in C++).
int nrows = 10;
int ncols = 15;
double** M = new double*[nrows];
for(unsigned long int i = 0; i < nrows; ++i)
M[i] = new double[ncols];
M[3][7] = 3.1416;
You'll rarely see this construct in normal C++ code, since C++ has references. It's useful in C for "passing by reference:"
int allocate_something(void **p)
{
*p = malloc(whatever);
if (*p)
return 1;
else
return 0;
}
The equivalent C++ code would use void *&p for the parameter.
Still, you could imagine e.g. a resource monitor like this:
struct Resource;
struct Holder
{
Resource *res;
};
struct Monitor
{
Resource **res;
void monitor(const Holder &h) { res = &h.res; }
Resource& getResource() const { return **res; }
}
Yes, it's contrived, but the idea's there - it will keep a pointer to the pointer stored in a holder, and correctly return that resource even when the holder's res pointer changes.
Of course, it's a dangling dereference waiting to happen - normally, you'd avoid code like this.
What is the second line? (Seen while answering another question.)
int * x = new int [1] ;
int * y = new (x) int;
After the second line x and y have the same value (point to a same place). What's the difference between y = x and the second line? Is it like a constructor or something?
It's placement new. It constructs a new int in the memory pointed to by x.
If you try:
int * x = new int [1];
*x = 5;
std::cout << *x << std::endl;
int * y = new (x) int;
*y = 7;
std::cout << *x << std::endl;
the output will be:
5
7
This is called placement new. It allows you to construct an object in memory already allocated.
This earlier thread discusses where and how it is useful for.
The second new is a "placement new". It performs initialization (i.e. call any necessary constructors) without doing any allocation. It is useful when you need to create a custom memory allocation scheme.
This is placement new.
Though you don;t usually use it with integer types.
It is usually used to build a buffer where you then build other types into.
// Allocate a buffer with enough room for two T objects.
char* buffer = new char[sizeof(T) * 2];
// Allocate a T in slot zero
T* t1 = new (buffer + 0 * sizeof(T)) T("Zero");
// Allocate a T in slot one
T* t2 = new (buffer + 1 * sizeof(T)) T("One");
Thats the basics.
But remember that the objects allocated with placement new can not be deleted with the delete statement. This is because delete tries to reclaim memory allocated by new (as well as call the destructor). So to use these objects correctly you must manually call there destructor.
t1->~T();
t2->~T();
Don't forget to delete the original buffer.
delete [] buffer;
A few other caveats:
People often see that buffer could be implemented on the stack and thus be automatically freed
char buffer[sizeof(T) * 2];
Unfortunately this may be technically OK (It compiles). But it is not guaranteed to work as the memory of buffer may not be aligned correctly for a T to be placed inside. So you must allocate the buffer dynamically (by using new it gurantees that the memory is aligned correctly for any object of the size allocated (thus by extension it is also aligned for any size smaller then the size allocated). The easy way to get around this problem is to use a std::vector
std::vector<char> buffer(sizeof(T) * 2);
T* t1 = new (&buffer[0] + 0 * sizeof(T)) T("Zero");
T* t2 = new (&buffer[0] + 1 * sizeof(T)) T("One");
Another use of placement new is to reset an object.
I have seen this done but I prefer to use the more standard assignment operator:
T obj1("Plop");
obj1 = T("Another Plop");
// Can be done like this:
T obj1("Plop");
obj1.~T();
new (&obj1) T("Another Plop"); // Seems excessive to me. But can be us-full
// in some extreme situations.
Remember if you use the reset method you must destroy the old object first (or the object may not behave correctly).
int * y = new (x) int;
This is as per placement new syntax.
EDIT: Along with custom allocation, placement new also helps to re-initialze an object state like below.
class Test
{
int startVal;
public:
Test()
{
startVal = 1;
}
void setVal(int val) { startVal = val; }
};
int main()
{
Test *p = new Test; //Creates new object and initializes it with
//a call to constructor.
p->setVal(10); //Change object content.
new(p) Test; //Reset object:
//object pointed by p will be re-initialzed here by making
//a call to constructor. startVal will be back to 1
}
As described in comments above, object state resetting also can be achieved using placement new.
placement new doesn't allocate memory, it constructs object at the specified address in the paranthesis.