What is an int() Called?
Asked Answered
W

3

15

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

Wheaten answered 12/12, 2014 at 12:19 Comment(6)
As an expression, int() and Foo() grammatically are "explicit type conversions" in the "functional notation", just like int(5), but with different rules. But I'd guess that only few people use that name to identify that feature.Frankiefrankincense
Adding to dyp, and the reason I marked as duplicate (did not know it would just close it immediately!), T() creates a value-initialized prvalueShelley
On the difference between compilers, VS is wrong. The rules for value-initialization require that Foo is zero-initialized, and that in turn means that _bar needs to get the value 0 in Foo()Shelley
@DavidRodríguez-dribeas Yeah there is a long exchange between Mike Seymour and myself in the comments on his answer, through which I came to see that.Wheaten
@JonathanMee: VS is known to have issues with different forms of value-initialization. I had a set of test cases that failed there for some time, and in my company we work around the compiler in a few cases.Shelley
Reopened the question, not truly a duplicate as the issue with this question is finding out that T() means value-initialization, rather than understanding what value-initialization means (which is the point of this other question: #1613841 )Shelley
Y
10

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.

Youthful answered 12/12, 2014 at 12:29 Comment(19)
@PiotrS.: Sorry, I didn't notice the private and used the wrong term. I'm sure it's still zero-initialised though.Youthful
@PiotrS.: Indeed it is: if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.Youthful
_bar is not initialized to zeroGales
@gldraphael: The entire class object is zero-initialised, which has the effect of initialising _bar to zero.Youthful
@MikeSeymour ah yes, you're right about the zero-initialization if the class has no user-provided construcorJag
@MikeSeymour I added a public method to Foo: void printBar(){ cout << _bar << endl; } When I call Foo().printBar() I get gibberish, not 0.Wheaten
@JonathanMee: I don't. Perhaps your compiler doesn't value-initialise the object according to the standard.Youthful
@JonathanMee or maybe you are not showing the exact class declaration, where different rules may applyJag
@MikeSeymour I've edited the question to demonstrate the calling of printBar.Wheaten
@JonathanMee: Your compiler is broken: connect.microsoft.com/VisualStudio/feedback/details/484295Youthful
@MikeSeymour I guess that's somehow a halfway bug with gcc too then?Wheaten
@JonathanMee: No, that's doing the right thing. The first is default-initialised, leaving it with an indeterminate value; the second is correctly zero-initialised.Youthful
@MikeSeymour I always thought those were the exact same. Thanks for the explanation. AND IF ANYONE FROM MICROSOFT IS LISTENING FIX YOUR COMPILER THIS WAS REPORTED 2 VERSIONS AGO!!!Wheaten
@MikeSeymour This is interesting: https://mcmap.net/q/17546/-meaning-of-default-initialization-changed-in-c-11/2642059 Did the standard change for C++11?Wheaten
@JonathanMee: The wording changed in C++11, but the reality described by the wording changed in C++03. The introduction of value initialization was the only non-bug-fix change in C++03. Otherwise C++03 was just TC1, Technical Corrigendum 1, a large bug-fix of C++98.Practically
@JonathanMee As you can test here, it was successfully fixed in vc2015Tamatamable
@Tamatamable Only 7 years and 3 versions after the bug report, sweet. None the less, I didn't realize they'd publicly released the preview, that's exciting.Wheaten
@MikeSeymour: visit also #3931812Meaganmeager
@MikeSeymour The foundation for what I know of initialization in C++ comes from this answer (scary I know.) Anyway Apparently I've misunderstood something and had to ask a follow up here: https://mcmap.net/q/332391/-how-do-zero-initialization-static-initialization-and-value-initialization-differ/2642059 Perhaps you'd grace me with a bit more clarification.Wheaten
P
6

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.)

Pacific answered 12/12, 2014 at 12:23 Comment(1)
Uhm... You almost nailed it, except that the better quote would be the next paragraph: *The expression T(), where T is a single-type-specifier... creates a prvalue of the specified type, which is value-initialized *Shelley
P
-1

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.

Practically answered 12/12, 2014 at 12:48 Comment(5)
@anonymous dowvoter: please state your disagreement openly, so I can show you the errors of your thinking. dunno if i can save you, but i'll try. :)Practically
@Cheersanhth.-Alf I'm not sure if I understood your last edit: "you have the same situation with any type without a user defined constructor" can you elaborate?Wheaten
@JonathanMee: I meant for the situation where a local isn't initialized. Sorry. I clarified that (the OP's incorrect assertion played havoc with this, I didn't see that his Foo was the type).Practically
Until reading you and Mike Seymour's comments I really didn't understand what "value-initialization" meant as far as a default ctor goes. <- signing up for the C++ beginner list :/Wheaten
@anonymous downvoter: That's like 3 downvotes with no explanation. We should get a duel going. Please stream, I will watch.Wheaten

© 2022 - 2024 — McMap. All rights reserved.