Sign in to follow this  

[C++] !NULL and new 'no throw'

This topic is 3788 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have been doing some reading today, and I have a pair of questions: 1) First lets consider the following example:
int* p = (int*)malloc(sizeof(int));
if (!p) //NULL indicates a failure
{
 cout<<"allocation failure!"
 exit(1);
}



Embarrassingly my question deals with the '!p' expression. I have done this a million times, but now that I think about this check it no longer makes any sense to me. - If the allocation failed then ptr is equal to NULL. NOT NULL is equal to true. - But if the allocation was successful ptr is equal to some 'non-zero value'. NOT some 'non-zero value' yields another non-zero value (unless the value is equal to 0xFF). The resulting value will also be equal to true. How come if(!p) works? Shouldn't it be if(p == NULL) ? 2) Second question deals with the definition of new in the nothrow case. The following syntax will suppress any possible bad_alloc exception that new may throw and have new return 0 on error like malloc does:
char *p = new(nothrow) char;
char *p = new(nothrow) char[count];



These operators are defined like this (in header <new>):
namespace std {
// throwing operators:
void* operator new(std::size_t size) throw(std::bad_alloc);
void* operator new[](std::size_t size) throw(std::bad_alloc);

// non-throwing operators
void* operator new(std::size_t size, const nothrow_t&) throw();
void* operator new[](std::size_t size, const nothrow_t&) throw();
}



I don't see how the usage matches the declaration. The definition seems to say that new is an operator that takes a size_t on the left and a const nothrow_t instance on the right. I suspect I am reading the operator definition incorrectly.

Share this post


Link to post
Share on other sites
Quote:
Original post by fpsgamer
NOT some 'non-zero value' yields another non-zero value (unless the value is equal to 0xFF).

You're confusing logical NOT (!) with bitwise complement (~).

Quote:
2) Second question deals with the definition of new in the nothrow case....I don't see how the usage matches the declaration.

operator-new signatures have a size_t as their first parameter, which is implicitly chosen as the sizeof the target type. This one has as its second parameter (aka the first placement parameter) a nothrow_t, a class with no member functions or variables, which exists only as a flag. "nothrow" is provided as a global variable of type nothrow_t.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
operator-new signatures have a size_t as their first parameter, which is implicitly chosen as the sizeof the target type. This one has as its second parameter (aka the first placement parameter) a nothrow_t, a class with no member functions or variables, which exists only as a flag. "nothrow" is provided as a global variable of type nothrow_t.


How does the first parameter get filled? ... I know you said it gets 'implicitly' filled, but does this mean that compiler treats 'new' as a special case? Or does the argument passing comply with conventional C++ argument passing.

Share this post


Link to post
Share on other sites
Quote:
Original post by fpsgamerNOT some 'non-zero value' yields another non-zero value

Does it? [wink]
Have you tried it recently?

Quote:

(unless the value is equal to 0xFF).

Not if you're doing a logical (as opposed to bitwise) not. The ! operator performs a logical not. It converts the value to a bool, and performs the not on that.
So !SomeNonZeroValue == false

Quote:

How does the first parameter get filled? ... I know you said it gets 'implicitly' filled, but does this mean that compiler treats 'new' as a special case? Or does the argument passing comply with conventional C++ argument passing.]

You could say that. All operators have slightly different syntax. (when you do a + b, how does the "operator +(..., ...)" get its arguments filled in?)

As far as the compiler is concerned, overloaded operators are just function calls. They just have a different syntax in the source code, but that doesn't really change how it's compiled.

Share this post


Link to post
Share on other sites
Quote:
Original post by fpsgamer
- If the allocation failed then ptr is equal to NULL. NOT NULL is equal to true.
- But if the allocation was successful ptr is equal to some 'non-zero value'. NOT some 'non-zero value' yields another non-zero value (unless the value is equal to 0xFF). The resulting value will also be equal to true.

How come if(!p) works? Shouldn't it be if(p == NULL) ?


As others have already said, !p is logical not -- it treats p as a simple boolean value, converting (for example) 0xBAADF00D to "true", and then taking the logical not of that (!true == false).

~p would be bitwise not, where the conversion to bool does not take place. I'm fairly confident that this operator isn't even defined for pointer types.

Quote:
I don't see how the usage matches the declaration.


Simply put, it just doesn't. Operator new is one of those operators that is a serious WTF?!? moment of the C++ standard. Also nonsensical is the difference between pre-increment and post-increment operators:

class A {
public:
void operator++() {}
void operator++(int) {}
};

void f() {
A a;
++a; // calls void A::operator++()
a++; // calls void A::operator++(int)
}


Obviously, there's no actual new integer being passed in the post increment version, but the call still changes. With operator new([]), at least this invisible parameter out of nowhere has a somewhat sensible value.

Share this post


Link to post
Share on other sites
Quote:

Quote:
I don't see how the usage matches the declaration.



Simply put, it just doesn't. Operator new is one of those operators that is a serious WTF?!? moment of the C++ standard.


But isn't it convenient that you don't have to pass sizeof(X) explicitly, as this is the value of the parameter that you want to pass anyway? (If you want more or less space for your type, you can use malloc.)

Another place where an argument is passed implicitly is the non-static member functions and the this pointer.

Share this post


Link to post
Share on other sites
Quote:
Original post by fpsgamer
Quote:
Original post by Sneftel
operator-new signatures have a size_t as their first parameter, which is implicitly chosen as the sizeof the target type. This one has as its second parameter (aka the first placement parameter) a nothrow_t, a class with no member functions or variables, which exists only as a flag. "nothrow" is provided as a global variable of type nothrow_t.


How does the first parameter get filled? ... I know you said it gets 'implicitly' filled, but does this mean that compiler treats 'new' as a special case? Or does the argument passing comply with conventional C++ argument passing.

operator new is not only an operator, it's also a keyword. As such, why can't one imagine a special treatment for this operator? And of course, there is a special treatment: where, in the code of operator new, do you call the class constructor? Why does Obj *o = new Obj() returns a pointer to an Obj instead of void*, despite the signature of operator new?

Using new is not as simple as calling a function. If it was one should call Obj *o = new(something,sizeof(Obj)), where something would be some type information (so that new would be able to call the constructor of Obj). This is quite convoluted with regard to the current syntax.

Now, the language allows you to override the way operator new allocates memory - this is done by creating an overload for the operator new() function. From an implementation point of view, the operator new() function overload has nothing to do with the call of new. They share the same name (for convenience), but they are different beasts.

Share this post


Link to post
Share on other sites

This topic is 3788 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this