What is an int() Called?

2.8k views Asked by At

It's been rehashed over and over that primitive types don't have constructors. For example this _bar is not initialized to 0 when I call Foo():

class Foo{
    int _bar;
};

So obviously int() is not a constructor. But what is it's name?

In this example I would say i is: (constructed? initialized? fooed?)

for(int i{}; i < 13; ++i)

Loki Astari mentions here that the technique has some sort of name.

EDIT in response to Mike Seymour:

#include <iostream>

using namespace std;

class Foo{
    int _bar;
public:
    void printBar(){ cout << _bar << endl; }
};

int main()
{
    Foo foo;

    foo.printBar();

    Foo().printBar();

    return 0;
}

Running this code on Visual Studio 2013 yields:

3382592
3382592

Interestingly on gcc 4.8.1 yields:

134514651
0

3

There are 3 answers

19
Mike Seymour On BEST ANSWER

It's been rehashed over and over that primitive types don't have constructors.

That's right.

For example this bar is not initialized to 0 when I call Foo()

Yes it is. Foo() specifies value-initialisation which, for class like this with no user-provided constructor, means it's zero-initialised before initialising its members. So _bar ends up with the value zero. (Although, as noted in the comments, one popular compiler doesn't correctly value-initialise such classes.)

It would not be initialised if you were to use default-initialisation instead. You can't do that with a temporary; but a declared variable Foo f; or an object by new F will be default-initialised. Default-initialisation of primitive types does nothing, leaving them with an indeterminate value.

It would also not be initialised if the class had a user-provided default constructor, and that constructor didn't specifically initialise _bar. Again, it would be default-initialised, with no effect.

So obviously int() is not a constructor. But what is it's name?

As an expression, it's a value-initialised temporary of type int.

Syntactically, it's a special case of an "explicit type conversion (functional notation)"; but it would be rather confusing to use that term for anything other than a type conversion.

In this example I would say i is: (constructed? initialized? fooed?)

Initialised. List-initialised (with an empty list), value-initialised, or zero-initialised, if you want to be more specific.

5
Cheers and hth. - Alf On

You can call it a pseudo-constructor if you want, mirroring the terminology for destructor (pseudo-destructor calls are discussed in C++11 ยง5.2.4). Anyway, int() is the default value of type int, i.e. 0.

Re the assertion that "primitive types don't have constructors", that's a rather silly and impractical view. From a formal point of view primitive types don't have constructors, but those who cling to that assertion aren't that much into the formal, at all. Also, from a machine code point of view they don't, but again, to those who think that assertion is important, machine code is like magic. There is a difference, though, namely that from a machine code point of view also common non-primitive POD types can lack constructors (they do have constructors formally), and again I doubt that those who put that assertion forward are even aware of the issues, i.e. I don't think they're qualified to have an opinion. About the same kind of considerations go for any absolute terminological claim: you can be almost sure, when you hear such a claim, that those who make it have almost no idea about what's involved, and that the claim is just impractical & silly.

Instead, when you hear e.g. "constructed" or "constructor call" in the context of primitive types, think about what it meaningfully can mean. The formal is just a matter of definition. The important, except for language lawyer discussions where it anyway is a given, is to have a conceptual model that works.


All the above said, the expression T() is not a "constructor" formally, it's not a constructor at the machine code level, and it's not a constructor conceptually, in any meaningful conceptual model.

It can be a constructor call (indeed the definition of a default constructor is that it can be called, at the source code level, with no arguments), but note that there's no grammar category for constructor calls.

With all of the above in mind I would just call it a constructor call, and when there is a need to be more precise, for primitive type T I would call it a pseudo-constructor call.


And if anyone criticized me for that, I'd just challenge them to a duel.


Do note, regarding your statement that

it's been rehashed over and over that primitive types don't have constructors. For example this bar is not initialized to 0 when I call Foo()

the expression Foo() performs value initialization, so that the instance (in this case) is zeroed.

Regarding the general lack of initialization of local automatic variables of primitive types without initializers, you have the same situation with any type without a user defined constructor, and even when there is a used defined constructor if that constructor doesn't initialize things.

This sometimes comes as a shock to C++ beginners.

1
Lightness Races in Orbit On

Here's what int() does (bearing in mind that, grammatically, int is a simple-type-specifier):

[C++11: 5.2.3/1]: A simple-type-specifier (7.1.6.2) or typename-specifier (14.6) followed by a parenthesized expression-list constructs a value of the specified type given the expression list. If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4). If the type specified is a class type, the class type shall be complete. If the expression list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1), and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as a prvalue.

Speaking colloquially, it represents the construction of a temporary int with an empty initialiser. I think you'd struggle to find a formal name for the entire construct, though.

This is not the same as int i{}, which is a full-fledged declaration of a named object with an initialiser: your i has been declared, constructed and initialised.

(I don't think that any of this is related to what Loki was saying in his comment on that linked answer.)