What happens on allocating with "new []" and deleting with just "delete" - c++

Okay, so i was experimenting with pointers in C++, as i have started to code again after almost an year and a half break(School Stuff). So please spare me if this seems naive to you, i am just rusting off.
Anyways, i was screwing around with pointers in VS 2019, and i noticed something that started to bug me.
This is the code that i wrote:
#include <iostream>
int main() {
int* i = new int[4];
*i = 323;
*(i + 1) = 453;
std::cout << *i << std::endl;
std::cout << *(i + 1) << std::endl;
delete i;
}
Something seems odd right? Dont worry, that delete is intentional, and is kindof the point of this question. Now I expected it to do some memory mishaps, since this is not the way we delete an array on the heap, BUT to my surprise, it did not(I did this in both Debug and Release and had the same observation)
Allocating the array:
First Modification:
Second Modification
Now i was expecting some sort of mishap at delete, since i did not delete it the way it is supposed to be deleted. BUT
Deleting Incorrectly
Now on another run i actually used the delete operator correctly and it did the same thing:
Now i got the same results when i tried to allocate with malloc and use delete to free it.
So my question is - Why does my code not mess up? I mean if this is how it works, I could just use delete (pointer) to wipe the entire array.
The gist of my question is "What does new operator do under the hood?"

What happens on allocating with “new []” and deleting with just “delete”
The behaviour of the program is undefined.
Now I expected it to do some memory mishaps
Your expectation is misguided. Undefined behaviour does not guarantee mishaps in memory or otherwise. Nothing about the behaviour of the program is guaranteed.
I mean if this is how it works
This is how you observed it to "work". It doesn't mean that it will necessarily always work like that. Welcome to undefined behaviour.

Related

Why is my value incorrect unless I use cout?

I'm making a C++ assignment for school and I've run into a peculiar problem. It's most likely memory corruption or whatever but as I am really mediocre at C++ I don't know how to solve it.
void Inventory::addItem(Item *item, const int stackCount) {
//find the item
Item *fi = findItem(item->id);
if(fi == nullptr)
{
Item *newItem = (Item *)malloc(sizeof(Item));
//std::cout << stackCount << std::endl;
memcpy(&newItem, &item, sizeof(Item));
newItem->stack = stackCount;
current.push_back(newItem);
}
}
I've got this piece of code, where it copies the Item's properties to another item. This works fine, and it carries everything over. Except something weird goes on with the stackCount variable.
There's a commented cout, and with it commented out the stackCount value is wrong. It will be at around 32k or so.
If it's not commented out, the value will be correct! Which is 1! (I am testing this in another function)
When placed behind the memcpy statement, the value is always wrong. Which of course leads me to believe that it's indeed memory corruption.
So I'm really quite confused. What exactly is c++ doing here?
memcpy(&newItem, &item, sizeof(Item));
What you're saying here is to copy from the address of item, aka a pointer to a pointer to an Item, to the address of newItem, aka another pointer to a pointer to an Item.
Since both of these are stack variables, and I'm guessing that sizeof(Item) != sizeof(Item**), you're invoking undefined behaviour here.
The reason the StackSize variable is only working when printing it is pure luck on your part; the compiler is most likeley just moving some variables around on the stack to try to optimize stack/register use, and moving the variable out of the area to be overwritten in the process.
Since you're using C++, you shouldn't be using memcpy in the first place. Write a copy constructor and an operator= instead to copy Item values.
Memcpy should get an address of destination and source.
You are passing "address to address".
Change:
memcpy(&newItem, &item, sizeof(Item));
to
memcpy(newItem, item, sizeof(Item));
Also, as stated by #Bathsheba and #Some-programmer-dude and #yksisarvinen, you shouldn't use malloc. Consider creating a copy constructor and/or assignment operator.

C++ new[] operator creates array of length = length + 1?

Why does the new[] operator in C++ actually create an array of length + 1? For example, see this code:
#include <iostream>
int main()
{
std::cout << "Enter a positive integer: ";
int length;
std::cin >> length;
int *array = new int[length]; // use array new. Note that length does not need to be constant!
//int *array;
std::cout << "I just allocated an array of integers of length " << length << '\n';
for (int n = 0; n<=length+1; n++)
{
array[n] = 1; // set element n to value 1
}
std::cout << "array[0] " << array[0] << '\n';
std::cout << "array[length-1] " << array[length-1] << '\n';
std::cout << "array[length] " << array[length] << '\n';
std::cout << "array[length+1] " << array[length+1] << '\n';
delete[] array; // use array delete to deallocate array
array = 0; // use nullptr instead of 0 in C++11
return 0;
}
We dynamically create an array of length "length" but we are able to assign a value at the index length+1. If we try to do length+2, we get an error.
Why is this? Why does C++ make the length = length + 1?
It doesn’t. You’re allowed to calculate the address array + n, for the purpose of checking that another address is less than it. Trying to access the element array[n] is undefined behavior, which means the program becomes meaningless and the compiler is allowed to do anything whatsoever. Literally anything; one old version of GCC, if it saw a #pragma directive, started a roguelike game on the terminal. (Thanks, Revolver_Ocelot, for reminding me: that was technically implementation-defined behavior, a different category.) Even calculating the address array + n + 1 is undefined behavior.
Because it can do anything, the particular compiler you tried that on decided to let you shoot yourself in the foot. If, for example, the next two words after the array were the header of another block in the heap, you might get a memory-corruption bug. Or maybe a compiler stored the array at the top of your memory space, the address &array[n+1] is aNULL` pointer, and trying to dereference it causes a segmentation fault. Or maybe the next page of memory is not readable or writable and trying to access it crashes the program with a protection fault. Or maybe the implementation bounds-checks your array accesses at runtime and crashes the program. Maybe the runtime stuck a canary value after the array and checks later to see if it was overwritten. Or maybe it happens, by accident, to work.
In practice, you really want the compiler to catch those bugs for you instead of trying to track down the bugs that buffer overruns cause later. It would be better to use a std::vector than a dynamic array. If you must use an array, you want to check that all your accesses are in-bounds yourself, because you cannot rely on the compiler to do that for you and skipping them is a major cause of bugs.
If you write or read beyond the end of an array or other object you create with new, your program's behaviour is no longer defined by the C++ standard.
Anything can happen and the compiler and program remain standard compliant.
The most likely thing to happen in this case is you are corrupting memory in the heap. In a small program this "seems to work" as the section of the heap ypu use isn't being used by any other code, in a larger one you will crash or behave randomly elsewhere in a seemingoy unrelated bit of code.
But arbitrary things could happen. The compiler could prove a branch leads to access beyond tue end of an array and dead-code eliminate paths that lead to it (UB that time travels), or it could hit a protected memory region and crash, or it could corrupt heap management data and cause a future new/delete to crash, or nasal demons, or whatever else.
At the for loop you are assigning elements beyond the bounds of the loop and remember that C++ does not do bounds checking.
So when you initialize the array you are initializing beyond the bounds of the array (Say the user enters 3 for length you are initializing 1 to array[0] through array[5] because the condition is n <= length + 1;
The behavior of the array is unpredictable when you go beyond its bounds, but most likely your program will crash. In this case you are going 2 elements beyonds its bounds because you have used = in the condition and length + 1.
There is no requirement that the new [] operator allocate more memory than requested.
What is happening is that your code is running past the end of the allocated array. It therefore has undefined behaviour.
Undefined behaviour means that the C++ standard imposes no requirements on what happens. Therefore, your implementation (compiler and standard library, in this case) will be equally correct if your program SEEMS to work properly (as it does in your case), produces a run time error, trashes your system drive, or anything else.
In practice, all that is happening is that your code is writing to memory, and later reading from that memory, past the end of the allocated memory block. What happens depends on what is actually in that memory location. In your case, whatever happens to be in that memory location is able to be modified (in the loop) or read (in order to print to std::cout).
Conclusion: the explanation is not that new[] over-allocates. It is that your code has undefined behaviour, so can seem to work anyway.

Is alocating specific memory for a void pointer undefined behaviour?

I've met a situation that I think it is undefined behavior: there is a structure that has some member and one of them is a void pointer (it is not my code and it is not public, I suppose the void pointer is to make it more generic). At some point to this pointer is allocated some char memory:
void fooTest(ThatStructure * someStrPtr) {
try {
someStrPtr->voidPointer = new char[someStrPtr->someVal + someStrPtr->someOtherVal];
} catch (std::bad_alloc$ ba) {
std::cerr << ba.what << std::endl;
}
// ...
and at some point it crashes at the allocation part (operator new) with Segmentation fault (a few times it works, there are more calls of this function, more cases). I've seen this in debug.
I also know that on Windows (my machine is using Linux) there is also a Segmentation fault at the beginning (I suppose that in the first call of the function that allocates the memory).
More, if I added a print of the values :
std::cout << someStrPtr->someVal << " " << someStrPtr->someOtherVal << std::endl;
before the try block, it runs through the end. This print I've done to see if there is some other problem regarding the structure pointer, but the values are printed and not 0 or negative.
I've seen these topics: topic1, topic2, topic3 and I am thinking that there is some UB linked to the void pointer. Can anyone help me in pointing the issue here so I can solve it, thanks?
No, that in itself is not undefined behavior. In general, when code "crashes at the allocation part", it's because something earlier messed up the heap, typically by writing past one end of an allocated block or releasing the same block more than once. In short: the bug isn't in this code.
A void pointer is a perfectly fine thing to do in C/C++ and you can usually cast from/to other types
When you get a seg-fault while initialization, this means some of the used parameters are themselves invalid or so:
Is someStrPtr valid?
is someStrPtr->someVal and someStrPtr->someotherVal valid?
Are the values printed is what you were expecting?
Also if this is a multuthreaded application, make sure that no other thread is accessing those variables (especially between your print and initialization statement). This is what is really difficult to catch

doubts in this program about classes- constructors and destructors

I have copied this code from a site.
But I am having problems understanding it properly.
Please can you help me these doubts.
I have written them as comments.
#include<iostream>
using namespace std;
#include<cstring>
class strings
{
char *m_string;
int m_length;
public:
strings(const char* str = "")
{
m_length = strlen(str) + 1;
m_string = new char[m_length];
strncpy(m_string,str,m_length);
m_string[m_length - 1] = '\0';/*1*/
}
~strings() /*2*/
{
delete[] m_string;
m_string = 0;/*3*/
}
char* get()
{
return m_string;
}
};
int main()
{
strings cstring("Alex");
cout << "Hi I am " << cstring.get();
cout << "\nsup";
strings cstrings1("Shady");
cout << "\nyo " << cstrings1.get();
return 0;
}
why is the code asking me to do this. When I removed this line code still worked perfectly fine
why are they using the destructor? Again not using it does seem to have any effect on the program
Also what is the use of doing this when I just used the delete keyword
Can you guys please explain to me in easy way really what do I use a destructor for? Thank you so much
1) Ensures that the string is null terminated - see http://www.cplusplus.com/reference/cstring/strncpy/ as to why this might not always be the case
2) It allows the delete operator to free up the allocated heap memory - otherwise your program will have a memory leak
3) Just good practice to avoid deleting previously deleted memory - this avoids undefined behaviour.
This is how to misuse C idioms in C++ to produce dangerous, error-prone programs. Don't use this as an example of how to write C++ effectively. To answer your specific questions:
In this case, explicitly terminating the C-style string is pointless. If you didn't know whether the input was small enough to fit in the array, then strncpy might truncate the string, and not put a zero terminator on the end; so, if you use strncpy, you must either terminate it yourself, or take some other action if it was truncated. But here you just allocated a large enough array, measured using strlen. You might as well use strcpy, memcpy or std::copy (which assume a large enough output array) instead of strncpy. Or, since this is C++ not C, throw the whole thing away and use std::string.
The destructor is needed to deallocate the memory allocated in the constructor. Otherwise you have a memory leak. As you say, this doesn't seem to have an effect - unless the program keeps allocating and leaking memory, in which case you'll eventually run out. You'll also need to define or delete a copy constructor and copy-assignment operator (per the Rule of Three), otherwise the class is not safe to copy.
That's pointless, since the pointer itself is about to be destroyed along with the rest of the class object. In some circumstances, if the pointer is going to persist after the delete, setting it to null would allow you to check whether or not it points to anything. But, unless you enjoy long debugging sessions, you shouldn't be using pointers for memory management anyway; use RAII types like smart pointers or std::string.

deleting an array the wrong way [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
How could pairing new[] with delete possibly lead to memory leak only?
I was always told that it's not safe to call delete on an array allocated with new[]. You should always pair new with delete and new[] with delete[].
So I was surprised to discover that the following code compiles and runs ok, in both Debug and Release mode under VS2008.
class CBlah
{
public:
CBlah() : m_i(0) {}
private:
int m_i;
};
int _tmain(int argc, _TCHAR* argv[])
{
for(;;)
{
CBlah * p = new CBlah[1000]; // with []
delete p; // no []
}
return 0;
}
It took me a while to figure out why this works at all, and I think it's just luck and some undefined behaviour.
BUT... it made me wonder... why doesn't Visual Studio pick this up, at least in the Debug memory manager? Is it because there's lots of code out there that makes this mistake and they don't want to break it, or do they feel it's not the job of the Debug memory manager to catch this kind of mistake?
Any thoughts? Is this kind of misuse common?
It will certainly compile ok, because there is no information in the pointer (compile-time) which will see if pointer points to array or what. For example:
int* p;
cin>>x;
if(x == 0)
p = new int;
else
p = new int [10];
delete p; //correct or not? :)
Now , about running ok. This is called undefined behavior in C++, that is, there is no guarantee what will happen - everything can run OK, you can get a segfault, you can get just wrong behavior, or your computer may decide to call 911. UB <=> no guarantee
It's undefined behavior and everything is fair in love, war and undefined behavior...:)
According to MDSN, it translates delete to delete[] when trying to delete an array. (See there, for instance). Though you should have a warning after compiling.
The reason the Debug Memory Manager does not pick up on this error is probably because it it not implemented at the level of new/delete, but at the level of the memory manager that gets invoked by new/delete to allocate the required memory.
At that point, the distinction between array new and scalar new is gone.
You can read these SO answers and links about delete and delete[]: About delete, operator delete, delete[], ...
I don't know what makes you think it "works ok". It compiles and completes without crashing. That does not mean necessarily there was no leak or heap corruption. Also if you got away with it this time, it doesn't necessarily make it a safe thing to do.
Sometimes even a buffer overwrite is something you will "get away with" because the bytes you have written to were not used (maybe they are padding for alignment). Still you should not go around doing it.
Incidentally new T[1] is a form of new[] and still requires a delete[] even though in this instance there is only one element.
Interesting point.
Once I did a code review and tried to convince programmers to fix new[]-delete mismatch.
I've argumented with "Item 5" from Effective C++ by Scott Meyers. However, they argumented with "What do you want, it works well!" and proved, that there was no memory leakage.
However, it worked only with POD-types. Looks like, MS tries to fix the mismatch as pointed out by Raveline.
What would happen, if you added a destructor?
#include <iostream>
class CBlah
{
static int instCnt;
public:
CBlah() : m_i(0) {++instCnt;}
~CBlah()
{
std::cout <<"d-tor on "<< instCnt <<" instance."<<std::endl;
--instCnt;
}
private:
int m_i;
};
int CBlah::instCnt=0;
int main()
{
//for(;;)
{
CBlah * p = new CBlah[10]; // with []
delete p; // no []
}
return 0;
}
Whatever silly"inteligence" fix is added to VS, the code is not portable.
Remember that "works properly" is within the universe of "undefined behavior". It is quite possible for a particular version of a particular compiler to implement this in such a way that it works for all intents and purposes. The important thing to remember is that this is not guaranteed and you can't really ever be sure it's working 100%, and you can't know that it will work with the next version of the compiler. It's also not portable, since another compiler might work in a different fashion.
This works because the particular C++ runtime library it was linked with uses the same heap for both operator new and operator new[]. Many do, but some don't, which is why the practice is not recommended.
The other big difference is that if CBlah had a non-trivial destructor, the delete p; would only call it for the first object in the array, whereas delete[] p; is sure to call it for all the objects.