Right way to delete pointer to pointer in C++ - c++

I have this simple example which fails in "delete poinerToBufferPointer":
char* buffer = new char[8];
memset(buffer, 1, 8);
char** poinerToBufferPointer = &buffer;
delete poinerToBufferPointer;
delete[] buffer;
But if I comment the "delete poinerToBufferPointer"
char* buffer = new char[8];
memset(buffer, 1, 8);
char** poinerToBufferPointer = &buffer;
//delete poinerToBufferPointer;
delete[] buffer;
it's working but the question is who will delete the double pointer?
Also very strange behavior is when I do delete on the pointer only it fail on delete[] buffer.
char* buffer = new char[8];
memset(buffer, 1, 8);
char** poinerToBufferPointer = &buffer;
delete *poinerToBufferPointer; // <--- only delete the pointer that points
delete[] buffer;
What is going on in memory, and what is the right way to delete both pointers?

You do not delete pointers, you delete the thing a pointer points to.
You only need to delete things you allocate with new
delete[] buffer; deletes the array pointed to by the pointer buffer. Since you allocated that with new[] that is correct.
delete pointerToBufferPointer; attempts to delete the pointer pointed to by pointerToBufferPointer. You did not allocate that pointer using new, however, so that is incorrect. A program that attempts to do that has undefined behavior.
If you had allocated the pointer pointed to by pointerToBufferPointer using new then you would need to delete it. For example, the following is correct (though you should almost never need to write code like this):
char** pointerToBufferPointer = new char*;
*pointerToBufferPointer = new char[8];
// ...
delete[] *pointerToBufferPointer;
delete pointerToBufferPOinter;
In most real code you should avoid using new and delete directly at all. For most common use cases, containers like std::string and std::vector that manage their own memory allocation for you are perfectly sufficient and much less error-prone.

Related

Why different ways of using "new" can make result uncompatible with " delete"? [duplicate]

This question already has answers here:
How serious is the new/delete operator mismatch error?
(4 answers)
Closed 1 year ago.
I'm reading C++ Primer Plus, 12.1.3, about memory, and some things about destructor really confuse me.
//Here is a default construtor of String class
String::String()
{
len = 0;
str = new char[1];
str[0] = '\0';
}
and the book says, use str = new char[1] not str = new char, the two ways allocate same memory, but the 2nd is not compatible with destructor. Besides, the book says the below 3 ways is bad because they are not compatible with "delete"
char words[15] = "bad idea";
char *p1 = words;
char *p2 = new char;
char *p3;
delete [] p1; //undefined, so don't do it
delete [] p2; //undefined, so don't do it
delete [] p3; //undefined, so don't do it
I don't know what are the difference that make these 3 ways bad, can someone explain it to me? Thank you very much.
new char[1] allocates a char array with a length of 1 while new char allocates a single char, these are fundamentally different.
In short, anytime you use new you would use delete to free the allocated memory. Anytime you use new[] you would use delete[] to free the allocated memory, that's just the rules.
Do note that while this is fine as a learning exercise nowadays there are more suitable alternatives. For example, for a dynamically allocated array you could use std::vector<char> instead of new char[] which has all the flexibility with none of the downsides such as manual memory management.
char words[15] = "bad idea";
char *p1 = words;
char *p2 = new char;
char *p3;
delete [] p1; //undefined, so don't do it
delete [] p2; //undefined, so don't do it
delete [] p3; //undefined, so don't do it
As you mentioned the book…
Hopefully, it also explained why these three delete[]s are undefined.
If not, here we go:
char words[15] = "bad idea";
char *p1 = words;
delete[] p1; //undefined, so don't do it
p1 was not allocated with new char[] but got the address of an array allocated on stack. Hence, it may not be delete[]-ed.
char *p2 = new char;
delete [] p2; //undefined, so don't do it
p2 was allocated with new. delete p2 has to be used instead of delete[] p2;. This is Undefined Behavior but I heard rumors that certain compilers handled it in such a similar way under the hood that it even works (probably).
char *p3;
delete[] p3; //undefined, so don't do it
Oh, oh. p3 is an uninitialized pointer.
Calling delete[] p3 is disastrous…
as the program will pick a random address and apply its heap memory book-keeping on it.
At best worst, your application will still work a bit further until it dies under mysterious conditions in something harmless like std::cout << std::endl; and you will have a hard time to find out where this comes from.
If the third case were
char *p3 = nullptr;
delete[] p3; // not undefined anymore
this would turn things into harmless.
delete (and delete[]) with a null pointer is a no-op and explicitly allowed.

delete[] and delete seems to behave alike

here if I use delete or delete[] the output is still 70. Can I know why?
#include<iostream>
using namespace std;
int main()
{
int* c = new int[100];
for(int i=0; i<98; i++)
{
c[i] = i;
}
cout<<c[70]<<endl;
delete[] c;
or
delete c;
cout<<c[70]<<endl; //outputs 70 even after delete[] or delete
return 0;
}
Accessing deleted memory is undefined behavior. Deleting with the wrong delete is also UB. Any further discussion is pointless in the sense that you cannot reliably expect any outcome.
In many cases, UB will just do the "correct" thing, but you need to be aware that this is completely "by chance" and could change with another compiler, another version of the same compiler, the weather... To get correct code, you need to avoid all cases of UB, even those that seemingly work.
Using new will just allocate some memory to your program and return a pointer pointing at the said memory address, reserving as much memory as needed for the datatype. When you use delete later, it "frees" the memory, but doesn't delete it's content. If you had an int with the value 70 stored at that address, it will still contain 70, until another application wants some memory, gets said address and puts another value in there.
If you use new to allocate memory for an array, you will reserve following blocks of memory until there are enough blocks for your specified array length.
Let's say you do the following:
int main() {
int* array = new int[10]; // array now points to the first block of the allocated memory
delete array; // since array points to the first block of the array, it will only free that block, but nothing else, causing a memory leak
delete[] array; // will free all memory allocated by the previous new
// Note that you should never free allocated memory twice, like in this code sample. Using delete on already freed memory is undefined behaviour!
]
Always use delete for single variables and delete[] for arrays.
A demonstration of your problem:
int main() {
int* c = new int[10]; // We allocate memory for an array of 10 ints
c[0] = 1; // We set the value of the first int inside the array to 1
delete[] c;
/*
* We free the previously allocated memory.
* Note that this does not delete the CONTENT of the memory!
* c does still point towards the first block of the array!
*/
std::cout << c[0];
/*
* Firstly, this is undefined behaviour (Accessing deallocated memory).
* However, this will output 1,
* unless some other process allocated the memory at the address
* and filled it with another value already. (Very unlikely)
*/
return 0;
}
If you want to delete / overwrite the content of the deleted memory, you can use std::memset.
Example:
#include <cstring>
int main() {
std::size_t length = 10;
int* c = new int[length];
c[0] = 1;
std::cout << c[0] << std::endl; // Will output 1
std::memset( c, 0, length ); // Fill the memory with 0 bytes
delete[] c; // Now we free the array's memory
std::cout << c[0] << std::endl; // Will output 0
}
As others pointed its undefined behaviour and anything can happen.
These can be easily caught with the help of tools like valgrind.

How delete char* array on mac osx using xcode?

int nSize;
QString str;
char *p = new char[nSize];
p = str.toLocal8bit.data();
delete[] p;
I got a debug error when I tried to delete a char array in Xcode 5.0.2 but this char array is successfully deleted in Xcode 3.0.2.
If it's deleted successfully anywhere, that's a bug.
char* p = new char[nSize];
So far so good. p is a char array.
p = str.toLocal8bit.data();
p now points to (presumably) some underlying data from str.toLocal8bit. You now have no way to reference the memory you just allocated.
delete[] p;
You've now deleted some other object's memory.
The line
p = str.toLocal8bit.data();
overwrites the pointer that you got from new. When you delete p you're deleting memory you don't control.
If you actually need a copy of the string data, you can use memcpy or strcpy to copy from the string to your array (instead of assigning).
If you don't actually need a copy, you could do:
const char* p = str.toLocal8bit.data();

Pointer Memory Leak

My pointer p is inside a function, will i get memory leak with this code.
for(k=0;k< 3;k++)
{
int *p=NULL;
int val = bBreak[k+1] - bBreak[k];
p = new int [val+1];
p = &buff[bBreak[k]];
for(int i=0;i< val;i++)
{
cout<<"\n"<<p[i]<<endl;
}
}
Yes! You never free the memory. You should call delete/delete[] for every piece of memory you allocate with new/new[].
Yes, you will
p = new int [val+1]; //allocate array on the heap
p = &buff[bBreak[k]]; //new allocated array is leaked because you lost the pointer to it
//and you are not able to call 'delete[]' to free the memory
Generally, every call to operator new should be paired with call of operator delete or delete[]
Yes. You must delete every memory you allocate with new.
p = new int [val+1];
p = &buff[bBreak[k]]; // here you lose track of the memory you've just allocated
If you don't want to do memory management by-hand, use a std::vector<int>.

How to copy values from one pointer to another

I have the following pointer:
jfloat *verticesLocal;
And I want make a new copy to:
jfloat *vertices;
I want to copy the values from verticesLocal to vertices.
How can I do that? I've just tried the following command, but it doesn't work:
memcpy(vertices, verticesLocal, numVerticesLocal * sizeof(jfloat));
I can't see the error because I'm working with Android native code. Sorry.
The idea of "copying a pointer", when taken literally, is nothing more than a simple assignment.
int x = 5;
int* p1 = &x;
int* p2 = p1; // there, we copied the pointer.
In this case, both p1 and p2 point to the same data - the int variable x. However, because this is so trivial, I'm inclined to think that what you really are asking about is how to copy the data that the pointer points to.
In this case, it depends on the data type. If the pointer points to a simple buffer of PODs, this involves allocating a separate buffer, and then using something like memcpy (or preferably std::copy) to copy the data. For example:
int* p1 = new int[100];
// ... fill p1 with values
int* p2 = new int[100]; // create a new buffer
std::copy(p1, p1 + 100, p2); // copy the data into p2
Or, you can use memcpy to copy the buffer byte-by-byte, since the buffer contains PODs.
memcpy(p2, p1, 100 * sizeof(int));
However, if the pointed-to data is not a simple buffer, but rather a C++ object, you can't use memcpy. You need to perform a deep copy of the object, (usually using the object's copy constructor) to get a clone of the object. How this is done, or whether it's even possible, depends on the object. (Some objects are noncopyable.)
I have no clue what a jfloat is, but if the object is, for example, an std::string, you would just do something like:
std::string* s1; // assume this points to a valid string
std::string* s2 = new std::string();
*s2 = *s1; // copies s1 using s2's assignment operator
In this contrived example it would be preferable to avoid heap-allocation altogether, and just use stack variables. But it demonstrates the idea of copying a heap-allocated object.
malloc first, then do your memcpy.
If you are copying the pointer, it is a simple assignment:
jfloat* verticesLocal; // assuming is is allocated already
jfloat* newVertices = verticesLocal;
IF you mean you want to copy the data the point points to, you have to allocate the memory for the new block of memory first:
// assume jfloat* verticesLocal is pointing to a valid memory block of size i
jfloat* newVertices = new jfloat[i];
memcpy(newVertices, verticesLocal, i * sizeof(jfloat));
this is how you copy an array buffer :
unsigned char *pBufferSrc = new unsigned char[10];
unsigned char *pBufCpd = new unsigned char[10];
for (int i = 0; i < 10; i++)
pBufferSrc[i] = i; // pBufferSrc = [0,1,2,3,4,5,6,7,8,9]
memcpy(pBufCpd, pBufferSrc, 10); // data from pBufferSrc is copied to pBufCpd (0,1,2,..9)
delete []pBufferSrc; // if even pBufferSrc buffer gets deleted, pBufCpd still has the data