How to default-initialize local variables of built-in types in C++?
Asked Answered
S

5

3

How do I default-initialize a local variable of primitive type in C++? For example if a have a typedef:

typedef unsigned char boolean;//that's Microsoft RPC runtime typedef

I'd like to change the following line:

boolean variable = 0; //initialize to some value to ensure reproduceable behavior
retrieveValue( &variable ); // do actual job

into something that would automagically default-initialize the variable - I don't need to assign a specific value to it, but instead I only need it to be intialized to the same value each time the program runs - the same stuff as with a constructor initializer list where I can have:

struct Struct {
   int Value;
   Struct() : Value() {}
};

and the Struct::Value will be default-initialized to the same value every time an instance is cinstructed, but I never write the actual value in the code.

How can I get the same behavior for local variables?

Sartor answered 6/4, 2010 at 10:50 Comment(5)
What are you trying to achieve? Mabe boxing the primitive variable in an object can help ?Bodgie
@clyfe: I don't want to have the actual value in my code since it doesn't matter.Sartor
I'm not sure what exactly you want. Do you want to automatically have T obj; default-initialize obj even for built-ins? That's not possible. Or do you just need a way to default-initialize obj no matter what type it is of? Then, as some answers already say, T obj = T(); is the way to go.Terpsichorean
On the other hand: boolean variable = retrieveValue() would not be bad either. And that's less typing :)Jussive
it seems very strange to want to initialise the variables to something but not care what. I wonder if you're trying to solve some bigger issue here and there might be a better way to approach that?Solvable
S
5

You can emulate that behaviour by the following:

boolean x = boolean();

or, more general,

T x = T();

This will default-initialize x if such a default-initialization exists. However, just writing T x will never do the trick for local variables, no matter what you do.

You can also use placement-new to invoke a “constructor”, even for POD:

T x;
new (&x) T();

Notice that this code produces undefined behaviour for non-POD types (in particular for types that have a non-trivial destructor). To make this code work with user-defined types, we first need to call the object’s destructor:

T x;
x.~T();
new (&x) T();

This syntax can also be used for PODs (guaranteed by §§5.2.4/12.4.15) so the above code can be used indiscriminately for any type.

Schatz answered 6/4, 2010 at 10:55 Comment(6)
I suppose for UDTs the latter raises UB, since the ctor isn't called on raw memory, but on an already constructed object.Terpsichorean
@sbi: true: for UDTs the latter must first call the destructor. I was only talking about PODs but I’ll clarify this to prevent misunderstandings.Schatz
x.~T(); indeed works in a template, where T is int. However, writing the same literally (x~int();) fails with both VC9 and Comeau.Terpsichorean
@sbi: so does GCC 4.4.2 with -pedantic. The grammar at §5.2 mentions that a type-name is valid here and this means class-name, enum-name or typedef-name. So fundamental types are indeed not allowed here – but typedefs to them are.Schatz
Indeed, at least VC9 accepts typedef int T; T x; x.~T();! I find this an annoying irregularity.Terpsichorean
@sbi: That’s built-in types for you. Similar exceptions apply to built-in types consisting of two (or more) lexemes. For example, try “default-constructing” an unsigned int (unsigned alone works fine, of course).Schatz
D
4
    int var = int();
    string str = string();
    ...

...or whatever typename you want.

Denominate answered 6/4, 2010 at 10:55 Comment(2)
In effect, this is not different from typing int var = 0; string str;Handbreadth
@kotlinski: yes but’s interchangeable. It works with every typename without the need to change the literal. Of course, for such code as the above this makes little sense. It makes more sense when used in conjunction with templates, however.Schatz
E
1

You could provide a wrapper that behaves as the underlying type through overloaded conversion operators.

#include <cassert>

template <class T>
class Type
{
    T t;
public:
    Type(const T& t = T()): t(t) {}
    operator T&() { return t; }
    operator const T&() const { return t; }
};

int main()
{
    Type<unsigned char> some_value;
    assert(some_value == '\0');
}

This should be a rather OK usage for conversion operators.

Euphonize answered 6/4, 2010 at 11:21 Comment(0)
D
0

Wrapping in the struct (Boolean) as in your example and accessing via a public member (Boolean::value). It may not be the most elegant solution (some cruft for small benefit), but it similar to what you already showed.

Dirty answered 6/4, 2010 at 10:56 Comment(0)
A
0

If I understand the original question, the poster is saying he wants variables of a given type to always have the same initial value, but he doesn't care what that value is, because he'll never look at it. Am I right?

If so, then my question for the poster is this: If you did not initialize the variables they would have random initial values... but you said you never look at initial values - so why does it matter if they're random?

I think the key question is - what are you trying to achieve here?

Antipus answered 6/4, 2010 at 11:29 Comment(3)
Uninitialized variables can introduce non-reproduceable behavior. The same variable might have different values on different program runs. That's what I don't want.Sartor
@joefis: If you want to ask for clarification on the question use comments, not answers.Dormie
> The same variable might have different values > on different program runs. OK, but that's only relevant if you access and use the values of uninitialized variables, which is a bug surely...Antipus

© 2022 - 2024 — McMap. All rights reserved.