tags:

views:

475

answers:

2

Does C++ do value initialization on simple POD typedefs?

Assuming

typedef T* Ptr;

does

Ptr()

do value-initialization and guarantee to equal (T*)0?

e.g.

Ptr p = Ptr();
return Ptr();
+16  A: 

It does. For a type T, T() value-initializes an "object" of type T and yields an rvalue expression.

int a = int();
assert(a == 0);

Same for pod-classes:

struct A { int a; };
assert(A().a == 0);

Also true for some non-POD classes that have no user declared constructor:

struct A { ~A() { } int a; };
assert(A().a == 0);

Since you cannot do A a() (creates a function declaration instead), boost has a class value_initialized, allowing to work around that, and C++1x will have the following, alternative, syntax

int a{};

In the dry words of the Standard, this sounds like

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

Since a typedef-name is a type-name, which is a simple-type-specifier itself, this works just fine.

Johannes Schaub - litb
I've been poring over the draft standard trying to figure this out. I'd forgotten about the typedef and was trying to figure out how a pointer type could be a simple-type-specifier (it's not), and now it makes sense: you can't do int*(), but you can do T() if T is typedef'ed to int*.
Adam Rosenfield
What about non POD type and POD members?
struct A { ~A() { } int a; }; is a non-pod type. Had you introduced a constructor yourself, then the value of "a" depends on what that constructor does, of course.
Johannes Schaub - litb
+1  A: 
#include <iostream>
struct Foo {
    char bar;
    char baz;
    char foobar;
    // the struct is a POD
    //virtual void a() { bar='b'; }
};

int main() {
    Foo o1;
    Foo o2 = Foo();

    std::cout << "O1: " << (int)o1.bar <<" "<< (int)o1.baz <<" "<< (int)o1.foobar << std::endl;
    std::cout << "O2: " << (int)o2.bar <<" "<< (int)o2.baz <<" "<< (int)o2.foobar << std::endl;
    return 0;
}

Output:

O1: -27 -98 0

O2: 0 0 0

Adding () propagates initializer calls to all POD members. Uncomenting the virtual method changes output to:

O1: -44 -27 -98

O2: -71 -120 4

However adding destructor ~Foo() does not suppress the initialization, although it creates non-POD object (output similar to first one).