How is "int* ptr = int()" value initialization not illegal?
Asked Answered
M

5

86

The following code (taken from here):

int* ptr = int();

compiles in Visual C++ and value-initializes the pointer.

How is that possible? I mean int() yields an object of type int and I can't assign an int to a pointer.

How is the code above not illegal?

Meaning answered 9/11, 2011 at 16:10 Comment(11)
Not an answer, but great question! I've never seen such a thing.Millenarian
Since primitives have a 'constructor' in C++, int() yields the value constructed value of int (which is I think a C++03 specified thing) and the default value of int is 0. This is equivalent to int *ptr = 0;Cocci
depending on the mashine, an int may be the same size as a pointer, but is should give you a warning.Pants
@EmanuelEy: No, any zero-valued integer constant can be used as a null pointer constant, regardless of how pointers are actually implemented.Tournedos
@MikeSeymour: NULL hasn't been allowed to be other values. Source: Stroustrup According to K&R NULL is always 0, which (in the context of a pointer) is converted to whatever the underlying null-pointer type is. So, in C++, NULL is 0, irrespective of the underlying hardware.Ruperto
@MooingDuck: I didn't say NULL could be a non-zero value. I said it could be any zero-valued integer constant (which includes int()).Tournedos
@MikeSeymour: I missed the word "zero". My bad.Ruperto
Also int isn't an object, even if you're using the object instantiation syntax to create one.Sampson
@fluffy: int is most certainly an object in C++.Ehling
@DanielPryden That is a use of the word "object" of which I was previously unaware.Sampson
Wow, this makes C++ sound like it's purely OO, like Python, where even POD's and functions are objects :)Geehan
F
110

int() is a constant expression with a value of 0, so it's a valid way of producing a null pointer constant. Ultimately, it's just a slightly different way of saying int *ptr = NULL;

Farwell answered 9/11, 2011 at 16:14 Comment(7)
+1, the constant expression bit is important and missing from the top-2 upvoted answers.Equidistant
does this go away with C++0x?Ottavia
@NeilG: This stays the same in C++11, though there is now also a nullptr, which you can use instead of 0 or NULL in new code.Farwell
Why use NULL instead of 0? All you do is type more.Reitareiter
@Nils: Code clarity and declaring your intent through code. Ofcourse, with C++11, now you want to use nullptr because it also tosses the benefit of extra compile-time checks into the mix.Imbed
C++ always leaves you with enough options to have a hour long discussion about trivial things. Now how is nullptr clearer than 0? ;)Reitareiter
@Reitareiter because quite obviously 0 could mean a null pointer constant or the number 0, while nullptr is obvious a null pointer constant. In addition, as Jamin said, it also has "extra compile-time checks". Do try to think before you type.Horten
E
35

Because int() yields 0, which is interchangeable with NULL. NULL itself is defined as 0, unlike C's NULL which is (void *) 0.

Note that this would be an error:

int* ptr = int(5);

and this will still work:

int* ptr = int(0);

0 is a special constant value and as such it can be treated as a pointer value. Constant expressions that yield 0, such as 1 - 1 are as well allowed as null-pointer constants.

Eckardt answered 9/11, 2011 at 16:13 Comment(12)
Also note that C's NULL isn't necessarily (void *)0 either. It's simply an implementation defined "integer constant expression with the value 0, or such an expression cast to type void *".Farwell
@JerryCoffin I've never used a C compiler which defined NULL as (void*)0; it was always 0 (or maybe 0L). (But then, by the time C90 had made (void*)0 legal in C, I was already using C++.)Doubletime
@JamesKanze: In ubuntu 11.04 and our own linux flavor, libio.h contains: #if !defined(__cplusplus) \n #define NULL ((void*)0) \n #else \n #define NULL (0) the current version of gcc in ubuntu is 4.5, in our system is 4.0.Equidistant
"0 is a special literal" - only because it's a constant expression, and it has the special value 0. (1-1) is equally special, it's also a null pointer constant, and so is int(). The fact of 0 being a literal is sufficient but not necessary condition to be a constant expression. Something like strlen(""), although it also has the special value 0, isn't a constant expression and hence isn't a null pointer constant.Harlandharle
@SteveJessop: I agree about the correction, it's really about the constant value 0, not the 0 literal.Eckardt
@DavidRodríguez-dribeas So Linux is trying to emulate all of the Microsoft errors? I haven't used C for almost 25 years, but in the K&R C that came with Unix back then, NULL was 0.Doubletime
@Tomalak: not really, since NULL is not guaranteed to be 0. It could be 0L, or 0LL. In my GCC installation, in contrast to David's, it's __null. It would be wrong to say "0 is NULL", although of course the value of NULL is 0 in some integer type.Harlandharle
@Steve: I just didn't like how NULL was being painted as some kind of separate, independent entity, that is "on the same standing" as 0, rather than something used to stand in for it (and for its friends).Unconcerned
@Tomalak: well, I don't like NULL at all, which is why I don't use it. I'm just excessively precise about its shortcomings ;-)Harlandharle
@Steve: I do, because I don't feel like manually replacing x% of my 0s when I switch to nullptr.Unconcerned
@Tomalak: yeah, not gonna bother replacing 0 with nullptr either. Might replace (void*)0 with nullptr, and will start using nullptr in preference to (void*)0, but since that would only appear in varargs calls and maybe a few places to force overload resolution, it's not a big code change. I write char *foo = 0; instead of char *foo = NULL/nullptr; for the same reason I write float f = 0; instead of float f = 0.0f;.Harlandharle
@JamesKanze: ISTR Borland C++ also defining NULL as (void*)0 for C (but not for C++. I always thought that the improved type safety of C++89 (what with function prototypes and the like) made this en vogue.Cheese
D
18

The expression int() evaluates to a constant default-initialized integer, which is the value 0. That value is special: it is used to initialize a pointer to the NULL state.

Doyen answered 9/11, 2011 at 16:13 Comment(2)
This is missing a very important detail present in Jerry's answer: it is not enough that the expression yields the value 0, but it must also be a constant-expression. For a counter-example, with int f() { return 0; }, the expression f() yields the value 0, but it cannot be used to initialize a pointer.Equidistant
@DavidRodríguez-dribeas, in my rush to present an answer in the simplest possible terms I left that part out. I hope it's acceptable now.Doyen
R
13

From n3290 (C++03 uses similar text), 4.10 Pointer conversions [conv.ptr] paragraph 1 (the emphasis is mine):

1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. [...]

int() is such an integral constant expression prvalue of integer type that evaluates to zero (that's a mouthful!), and thus can be used to initialize a pointer type. As you can see, 0 is not the only integral expression that is special cased.

Regime answered 9/11, 2011 at 16:20 Comment(0)
C
4

Well int isn't an object.

I beleive what's happening here is you're telling the int* to point to some memory address determined by int()

so if int() creates 0, int* will point to memory address 0

Cesium answered 9/11, 2011 at 16:13 Comment(5)
int() most certainly is an object.Unconcerned
@Tomalak: I don't think it is. It's a temporary of non-class type, and I think I'm right in saying that these are not objects as far as the C++ standard is concerned. It's a bit odd, though, the section on "temporary objects" starts out carefully talking only about temporaries of class type, but later on it talks about binding references, and of course you can bind a reference to int(). Define int i;, then no question, i is an object.Harlandharle
@Steve: I'd only expect debate over this in that "objects" are a region of storage in C++, and temporaries don't really have storage, right? 1.8/1 doesn't explicitly list temporaries, but it feels as if the intent is there to include them.Unconcerned
@Tomalak: yes indeed, temporaries of non-class type don't need storage unless you take a reference. Never mind though, it doesn't matter much. The statement "well int isn't an object" is only true because int is a type, not an object. Whether int() yields an object or just an rvalue doesn't affect anything anyone has said elsewhere.Harlandharle
@Steve: That much is undebateable :)Unconcerned

© 2022 - 2024 — McMap. All rights reserved.