new/delete exception

This example was intended to throw an exception by allocating more memory than is available, but instead it succeeds.

sizeof(*pointer) = 4 (size of 1st int = 4 bytes)
sizeof(pointer) = 8 (size of the whole block?????, seems like size of the pointer itself on x64 ???)

Should'nt sizeof(pointer) give me the size of the whole block of allocated memory?

How much memory is attempted to be allocated?

0x1fffffff = 536,870,911 integers *4 bytes = 2,147,483,644.....is this 2+ Terabytes of attempted memory allocation?



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;


int main()
{
	int* pointer = new(nothrow) int [0x1fffffff];
	
	if (pointer)
	{
		cout << "SUCCESS" << endl;
		cout << "sizeof(*pointer) = " << sizeof(*pointer) << endl;
		cout << "sizeof(pointer) = " << sizeof(pointer) << endl;
		delete[] pointer;
	}
	else
		cout << "FAILED" << endl;
}
sizeof gives the number of bytes used by the given argument. For a pointer this will be either 4 or 8 depending upon compiled for 32 or 64 bit. For a non-pointer it is the number of bytes used for that type. So eg int will usually be 4 and long long int will usually be 8.

Given a pointer, there is no standard method of determining how many bytes have been allocated for that pointer.
SubZeroWins wrote:
This example was intended to throw an exception ...

Your use of nothrow disabled exceptions. Instead of throwing a std::bad_alloc exception it would return a null pointer.

SubZeroWins wrote:
sizeof(pointer) = 8 (size of the whole block?????, seems like size of the pointer itself on x64 ???)

Yes, sizeof(pointer) will give you the size of the pointer which is typically 8 bytes (64 bits) on 64-bit systems.

SubZeroWins wrote:
0x1fffffff = 536,870,911 integers *4 bytes = 2,147,483,644.....is this 2+ Terabytes of attempted memory allocation?

No. It's only 2 GB.

Note that detecting memory allocation failures are not entirely reliable because some systems do not actually allocate physical memory until the memory is used. This means that a large allocation might succeed even if there is not enough physical memory and instead crash the program later when it tries to use the memory.
Last edited on
So I guess there is no need for sizeof to report the full memory allocation of the dynamically allocated pointer, since you would have known the number to begin with & you simply do the math * sizeof(type).

I did not know it can falsify assignment. It actually did not return a NULL, so it must be the case. But it does not make sense why, since nothrow is designed to prevent any crashes & this can then lead to a crash.

Oh yes, 2GB (bytes, KB, MB, GB).

One other question. Do you guys really assign a pointer to NULL & back to NULL after delete for safety measures, religiously? Or do you see a mixed bag with code in the wild? Do you always check for "if (pointer)" before dereferencing it? I just derefernce pointers in my practice, but maybe I should just start practicing the full & correct way.

Last edited on
There are smart pointers that track their own existence and only self-delete after all references have been destroyed. Many here would suggest that you use those rather than create your own memory management system.

If you want to create your own memory management system, then it is highly recommended that you set pointers to NULL on delete. It gives you a safe way to check if the address still exists without crashing the whole program.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void myFunction(className & myObject)
{
    if(myObject.image != NULL)
    {
       // wohoo! we can continue.
    }
    else
    {
        // Tell the programmer that something went wrong, 
        // if myObject has a name then we can tell programmer what object is having issue
        // and we already know what function we're in, so let's tell them that too.

        // but we can choose to close the program, or just not draw this image.
    }
}


While you're on the topic of pointers, look up the fly-weight pattern for reducing total used memory by sharing assets (very useful in games with repeating images/textures).
Last edited on
SubZeroWins wrote:
So I guess there is no need for sizeof to report the full memory allocation of the dynamically allocated pointer, since you would have known the number to begin with & you simply do the math * sizeof(type).

Yes, but note that there might be some overhead, so the memory usage might be slightly more. This is probably nothing you need to worry about unless you do a lot of very small allocations.

SubZeroWins wrote:
I did not know it can falsify assignment. It actually did not return a NULL, so it must be the case.

Not necessarily. Maybe you have 2 GB of free memory. Note that it is not just about the RAM memory that is available. It's common to have a small area on disk that can be used if you run out of RAM. This is sometimes called a "swap partition" or "swap file". It's slower but it means the program doesn't need to fail just because you happen to use slightly more memory than the amount of RAM that you have.

Compare the two following programs. Look at the memory usage on your computer.
1
2
3
4
5
6
7
#include <iostream>

int main()
{
	int* pointer = new int [0x1fffffff]; // uninitialized (unused memory)
	std::cin.get();
}

1
2
3
4
5
6
7
#include <iostream>

int main()
{
	int* pointer = new int [0x1fffffff](); // initialized (used memory)
	std::cin.get();
}

For me (on Linux) the memory usage for the first program is neglectable while the second program makes the memory usage go up by 2 GB.

SubZeroWins wrote:
But it does not make sense why, since nothrow is designed to prevent any crashes & this can then lead to a crash.

It's not really how the standard describe that things should work, but it's a trade-off. If you don't allow "overcommitting" then you might instead waste memory.

I wouldn't say the purpose of nothrow is to prevent crashes. I think the purpose is to avoid that an exception is thrown. A program can catch exceptions so if an exception gets thrown it doesn't necessarily mean the program has to "crash". Even if you do not catch the exception it's not like a segfault or std::abort because destructors of local and global variables will still get called.

SubZeroWins wrote:
Do you guys really assign a pointer to NULL & back to NULL after delete for safety measures, religiously?

If I create a pointer that is not pointing to anything I always initialize it to null.

I don't use new/delete very often. Normally I prefer to just create objects as regular variables, and when I need to dynamically allocate the objects I would normally use std::unique_ptr which would automatically ensure the pointer is set to null appropriately. To store many objects of the same type I would normally use a container such as std::vector.

If I used new and delete manually (which was common before C++11) then I would not set the pointer to null if it was destroyed right after. For example, if I had a class that had a pointer as a member variable, and if I used delete on the pointer in the destructor I would not set it to null after because the object (and the pointer) would get destroyed and there was no chance someone used the pointer afterwards. However, if I had to use delete in some of the member functions I would set it to null because other member functions (including the destructor) that might be called afterwards need to know that the pointer doesn't point to anything.

SubZeroWins wrote:
Do you always check for "if (pointer)" before dereferencing it?

No. Not if I "know" that it should not be null. It might be a class invariant or it might be a precondition of the function. In that case I might sometimes use assert instead but not all over the place, it depends...

https://en.wikipedia.org/wiki/Precondition
https://en.wikipedia.org/wiki/Invariant_(mathematics)#Invariants_in_computer_science
Last edited on
Do you guys really assign a pointer to NULL & back to NULL after delete for safety measures, religiously?


Pointers should always be initialised when defined - either to a correct value or to nullptr. Unless in a destructor, IMO a pointer should be set to nullptr after a delete. Whether you test for nullptr before dereferencing is dependent upon whether a nullptr value can be valid, and if not whether you want to terminate the program gracefully or just get a run-time abort. Note that continually checking for nullptr can have a performance overhead.
Last edited on
> Do you guys really assign a pointer to NULL & back to NULL after delete for safety measures, religiously?

It is not a panacea. Pointers may be aliased; setting one of them (the one which was used in the delete expression) alone to nullptr may not buy us much.


> Do you always check for "if (pointer)" before dereferencing it?

In general yes.
If a nullptr value is an invalid value, favour using a reference instead.

A pointer (T*) can be a nullptr and a reference (T&) cannot, there is no valid “null reference”. Sometimes having nullptr as an alternative to indicated “no object” is useful, but if it is not, a reference is notationally simpler and might yield better code.
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-ptr-ref

Topic archived. No new replies allowed.