Reputation:
I'm trying to a bit modified of built-in allocation function:
#include <iostream>
#include <cstdlib>
#include <new>
struct A
{
int a;
A(){ std::cout << "Constructor\n"; a = 3; }
void* operator new(std::size_t t) noexcept
{
::operator new(t);
return NULL;
}
};
int main()
{
new A();
}
Instead of constructor call I've got segmentation fault
. Could you explain that behavior?
Upvotes: 8
Views: 964
Reputation: 283921
You have a bug, because the call to ::operator new()
could throw std::bad_alloc
, violating the exception-specification of your class-specific allocator (zybox's answer shows how to fix this). However, that's very unlikely to happen in such a small program. It's also a bad idea to override operator new()
without also providing operator delete()
, although I can't find an explicit requirement that both must be found in the same scope.
Returning a null pointer from your allocator is both legal and the correct way to indicate an allocation failure. In 3.7.4.1, the Standard says that:
An allocation function that fails to allocate storage can invoke the currently installed new-handler function (18.6.2.3), if any. [ Note: A program-supplied allocation function can obtain the address of the currently installed
new_handler
using thestd::get_new_handler
function (18.6.2.4). — end note ] If an allocation function declared with a non-throwing exception-specification (15.4) fails to allocate storage, it shall return a null pointer. Any other allocation function that fails to allocate storage shall indicate failure only by throwing an exception (15.1) of a type that would match a handler (15.3) of type std::bad_alloc (18.6.2.1).
Then in 5.3.4:
If the allocation function returns null, initialization shall not be done, the deallocation function shall not be called, and the value of the new-expression shall be null.
The code is legal on the path that ::operator new()
doesn't throw -- the expression new A()
in main()
evaluates to a null pointer, which is ok because it never gets dereferenced.
You shouldn't get a constructor call either. What you should get is a memory leak, since there is no ::operator delete()
call corresponding to the ::operator new(t)
inside your allocator.
Upvotes: 5
Reputation: 188
The original code simply returns NULL
from A::operator new
, quietly forgetting the return result of ::operator new
(a memory leak). The reason for the crash is that the pointer returned is then used as the this
pointer for the new A
object. Since that pointer is NULL
, anything the constructor does with the object (assigning a = 3
) is dereferencing NULL
. That results in a segmentation violation. zyboxinternational's answer above gives a good solution, and the comments of both previous posters are very relevant.
Upvotes: 0
Reputation: 4561
Your function operator new
contains a null
pointer, and as such doesn't actually return anything.
The null
function operator is equal to return false;
, or just return;
, but be warned: duplicating a pointer using the new
operator causes memory leaks if you aren't careful. To get around this, just delete(t)
when you're done.
The following code will fix your issue:
#include <iostream>
#include <cstdlib>
#include <new>
struct A
{
int a;
A(){ std::cout << "Constructor\n"; a = 3; }
void* operator new(std::size_t t) noexcept
{
return ::operator new(t, std::nothrow);
}
};
int main()
{
new A();
}
Upvotes: 1