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?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • Not an answer, but great question! I've never seen such a thing. – Josh Nov 09 '11 at 16:12
  • 6
    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;` – wkl Nov 09 '11 at 16:13
  • depending on the mashine, an int may be the same size as a pointer, but is should give you a warning. – Emanuel Ey Nov 09 '11 at 16:15
  • 7
    @EmanuelEy: No, any zero-valued integer constant can be used as a null pointer constant, regardless of how pointers are actually implemented. – Mike Seymour Nov 09 '11 at 16:16
  • @MikeSeymour: `NULL` hasn't been allowed to be other values. Source: [Stroustrup](http://www2.research.att.com/~bs/bs_faq2.html#null) According to [K&R](http://www.faqs.org/faqs/C-faq/faq/) `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. – Mooing Duck Nov 09 '11 at 16:49
  • 1
    @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()`). – Mike Seymour Nov 09 '11 at 16:57
  • @MikeSeymour: I missed the word "zero". My bad. – Mooing Duck Nov 09 '11 at 17:22
  • Also `int` isn't an object, even if you're using the object instantiation syntax to create one. – fluffy Nov 09 '11 at 18:41
  • @fluffy: [`int` is most certainly an object](http://www.parashift.com/c++-faq-lite/classes-and-objects.html#faq-7.2) in C++. – Daniel Pryden Nov 09 '11 at 21:02
  • 5
    @DanielPryden That is a use of the word "object" of which I was previously unaware. – fluffy Nov 09 '11 at 21:43
  • Wow, this makes C++ sound like it's purely OO, like Python, where even POD's and functions are objects :) – legends2k Dec 31 '12 at 15:32

5 Answers5

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;

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 3
    +1, the *constant expression* bit is important and missing from the top-2 upvoted answers. – David Rodríguez - dribeas Nov 09 '11 at 16:43
  • does this go away with C++0x? – Neil G Nov 09 '11 at 22:45
  • @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. – Jerry Coffin Nov 09 '11 at 23:02
  • Why use NULL instead of 0? All you do is type more. – Nils Jul 13 '12 at 07:13
  • 2
    @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. – Jamin Grey Feb 27 '13 at 01:07
  • C++ always leaves you with enough options to have a hour long discussion about trivial things. Now how is nullptr clearer than 0? ;) – Nils Feb 27 '13 at 08:43
  • 3
    @Nils 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. – Miles Rout Jun 11 '14 at 06:34
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.

Blagovest Buyukliev
  • 42,498
  • 14
  • 94
  • 130
  • 1
    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 *". – Jerry Coffin Nov 09 '11 at 16:52
  • @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++.) – James Kanze Nov 09 '11 at 17:07
  • 1
    @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. – David Rodríguez - dribeas Nov 09 '11 at 17:33
  • 5
    "`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. – Steve Jessop Nov 09 '11 at 17:37
  • @SteveJessop: I agree about the correction, it's really about the constant value `0`, not the `0` literal. – Blagovest Buyukliev Nov 09 '11 at 18:00
  • @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. – James Kanze Nov 09 '11 at 18:37
  • @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. – Steve Jessop Nov 09 '11 at 23:31
  • @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). – Lightness Races in Orbit Nov 09 '11 at 23:32
  • @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 ;-) – Steve Jessop Nov 09 '11 at 23:33
  • @Steve: I do, because I don't feel like manually replacing `x`% of my `0`s when I switch to `nullptr`. – Lightness Races in Orbit Nov 09 '11 at 23:34
  • @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;`. – Steve Jessop Nov 09 '11 at 23:48
  • @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. – sbi Nov 22 '11 at 13:09
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.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 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. – David Rodríguez - dribeas Nov 09 '11 at 16:44
  • @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. – Mark Ransom Nov 09 '11 at 16:51
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.

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
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

Megatron
  • 2,871
  • 4
  • 40
  • 58
  • 1
    `int()` most certainly _is_ an object. – Lightness Races in Orbit Nov 09 '11 at 19:14
  • @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. – Steve Jessop Nov 09 '11 at 23:36
  • @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. – Lightness Races in Orbit Nov 09 '11 at 23:41
  • 1
    @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. – Steve Jessop Nov 09 '11 at 23:43
  • @Steve: That much is undebateable :) – Lightness Races in Orbit Nov 09 '11 at 23:45