How do I value-initialize a Type* pointer using Type()-like syntax?
Asked Answered
N

7

14

Variables of built-in types can be value-initialized like this:

int var = int();

this way I get the default value of int without hardcoding the zero in my code.

However if I try to do similar stuff for a pointer:

int* ptr = int*();

the compiler (Visual C++ 10) refuses to compile that (says type int unexpected).

How do I value-initialize a pointer in similar manner?

Nomarch answered 9/11, 2011 at 15:47 Comment(2)
Good question. You also get a similar failure for unsigned int.Micahmicawber
Now the question is why would you want to do that. You can initialize pointers with 0 directly (if you know it is a pointer), and if this is hidden in some template, then T() will work fine... I don't get how this question gets 11 upvotes :)Chronon
R
4

How do I value-initialize a Type* pointer using Type()-like syntax?

You cannot. The syntax T() is defined in 5.2.3/1,2 (C++03, slightly different wording in C++11 FDIS). In particular the second paragraph states:

The expression T(), where T is a simple-type-specifier (7.1.5.2) for a non-array complete object type or the (possibly cv-qualified) void type, creates an rvalue of the specified type, which is value-initialized (8.5);

That means that int(), will create an rvalue of type int and value-initialize it. Now the problem is that int* is not a simple-type-specifier, but rather an elaborated-type-specifier. The definition of simple-type-specifier in the grammar is:

  simple-type-specifier:
    ::opt nested-name-specifieropt type-name
    ::opt nested-name-specifier template template-id
    char
    wchar_t
    bool
    short
    int
    long
    signed
    unsigned
    float
    double
    void

With type-name being defined as:

  type-name:
    class-name
    enum-name
    typedef-name

This is what makes the proposed solutions work. The creation of the typedef (either directly or through the template) creates a type-name (third type) that can be used as a simple-type-specifier (first type).

Release answered 9/11, 2011 at 16:35 Comment(0)
C
9

Use a typedef to make a name for your pointer type:

typedef int *ip;

ip ptr = ip();

The same idea should work for other types that require more than one lexical element (word) to define the name of the type (e.g., unsigned long, long long, unsigned long long *, etc.).

Camellia answered 9/11, 2011 at 15:54 Comment(3)
I'm confused, a pointer just holds the address in memory of the variable - shouldn't it just be int* x = int(), making x hold 0 which is the same as NULL? I guess I'm missing something since people keep skipping past mine, haha, I don't get what though.Telophase
@w00te: Yours will have the same effect, because 0 is defined to convert to a null pointer. At the same time, he's specifically asking about how to do value initialization, and you're doesn't do that ("value initialization" has a specific defined meaning in the C++ standard that's a bit different from just the general idea of initializing with a value).Camellia
Ah, I figured he just wanted to make sure his pointer pointed to null so it could be checked more effectively in later code :) Guess I misread.Telophase
R
4

How do I value-initialize a Type* pointer using Type()-like syntax?

You cannot. The syntax T() is defined in 5.2.3/1,2 (C++03, slightly different wording in C++11 FDIS). In particular the second paragraph states:

The expression T(), where T is a simple-type-specifier (7.1.5.2) for a non-array complete object type or the (possibly cv-qualified) void type, creates an rvalue of the specified type, which is value-initialized (8.5);

That means that int(), will create an rvalue of type int and value-initialize it. Now the problem is that int* is not a simple-type-specifier, but rather an elaborated-type-specifier. The definition of simple-type-specifier in the grammar is:

  simple-type-specifier:
    ::opt nested-name-specifieropt type-name
    ::opt nested-name-specifier template template-id
    char
    wchar_t
    bool
    short
    int
    long
    signed
    unsigned
    float
    double
    void

With type-name being defined as:

  type-name:
    class-name
    enum-name
    typedef-name

This is what makes the proposed solutions work. The creation of the typedef (either directly or through the template) creates a type-name (third type) that can be used as a simple-type-specifier (first type).

Release answered 9/11, 2011 at 16:35 Comment(0)
U
3

Doesn't require the use of typedef (but exclusive to C++11), which can be useful when dealing with several pointer types:

template<typename T>
using alias = T;

then alias<int*> is int*, so you can do int* p = alias<int*>().

A similar solution available to C++03, using an identity metafunction:

template<typename T>
struct identity {
    typedef T type;
};

int* p = identity<int*>::type();
Undulate answered 9/11, 2011 at 16:8 Comment(1)
The C++03 version requires a typedef, it is just hidden inside a template. The C++11 version does not create a typedef, but it does create a new type alias<T> which becomes a simple-type-specifier and thus prone to explicit type conversion in the functional notationChronon
T
1

Just do

int* x = int();

It still assigns 0 to the pointer making it point to the NULL address since you're defaulting it with the default value of int which is 0 anyway.

Actually, it works fine for all types:

double* y = int();

The address is still a 32-bit (or 64-bit depending on platform) integer so I think it should work fine for all types if you do = int().

Telophase answered 9/11, 2011 at 15:53 Comment(3)
Wow, looks like a major breach in the type system and is unbelievably cool. Yet it won't work for double*.Nomarch
huh, interesting :) I'll have to check that out. I'd have thought it would have worked for all pointer types.Telophase
Yes, I meant double* ptr = double() which of course won't work.Nomarch
M
1

Here's one way:

template <typename T>
T make_default()
{
    return T();
}

int main()
{
    int *p = make_default<int*>();
}
Mana answered 9/11, 2011 at 15:53 Comment(0)
P
0

The reason that doesn't work is because pointers do not have constructors.

The syntax

int ()

calls (in theory)

int::int ()

which initializes the variable. (More likely, the compiler just zeros the variable, but that's because it "knows" about ints).

In c++11, you can use nullptr

int *ptr = nullptr;

Otherwise, you pretty much have to use NULL:

int *ptr = NULL;

Pard answered 9/11, 2011 at 15:55 Comment(1)
Of course pointers have constructors in the same way int has — it's all built-ins, after all. I can say T() if T is typedef int* T, and I cannot use = unsigned int() either. It's the just the purely syntactic problem of this not working with composite type names.Methedrine
E
-1

This is how you do it int* ptr = new int;

Heap pointers

Electrothermal answered 9/11, 2011 at 15:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.