Pergunta

I know that, in C++, when you write

int i;

you can not make any assumptions about the value that the variable will hold until you effectively assign it a value. However, if you write

int i = int();

then you have the guarantee that i will be 0. So my question is, isn't it actually an incosistency in the behavior of the language? I mean, if I have defined a class MyClass and write

MyClass myInstance;

I can rest assured that the default constructor without parameters of the class will be called to initialize myInstance (and the compiler will fail if there is none), because that's how the RAII principle goes. However, it seems that when it comes to primitive types, resource acquisition is not initialization anymore. Why is that?

I don't think that changing this behavior inherited from C would break any existing code (is there any code in the world that works on the assumption that no assumption can be made about the value of a variable?), so the main possible reason that comes to my mind is performance, for example when creating big arrays of primitive types; but still, I'd like to know if there is some official explanation to this.

Thanks.

Foi útil?

Solução

No. It is not inconsistency.

What if your class is defined as:

struct MyClass
{
    int x;
    float y;
    char *z;
};

then this line does NOT do that you think it does:

MyClass myInstance; 

Assuming the above is declared inside a function, it is same as:

int x; //assuming declared inside a function

In C++, the types are broadly divided into 3 kinds viz. POD, non-POD, Aggregates — and there is a clear distinction between them. Please read about them and their initialization rules (there are too many topics on them. Search on this site). Also read about static initialization and dynamic initialization.

Outras dicas

The real reason, at least initially, was that C++ wanted all objects which are compatible with C to behave exactly as they would in C. The reason in C was (and still is) performance; zero initialization of objects with static lifetime was free (because the OS must initialize all memory that it gives the process anyway, for security reasons); zero initialization otherwise costs runtime. (The performance rationale is less strong today than it was originally, because compilers are a lot better at determining that the variable will be initialized later, and suppressing the zero-initialization in such cases; but they do still exist; in particular, in cases like:

char buffer[1000];
strcpy( buffer, something );

If zero initialization were required, I don't know of any compiler which would be able to skip it here, even though it won't be necessary.)

If you write

int i;

then the initialization or not depends on the context.

  • Namespace scope → zero-initialized.
  • Local function scope → uninitialized.
  • Class member: depends on the constructors, if any.

The lack of initialization for a local variable is just for efficiency. For a very simple function that is called repeatedly at the lowest levels, this can matter. And C and C++ are languages used to construct the bottom levels of things.

When you set a local variable in a function to some value, then every time the function is called, the assignment takes place and the value is loaded into the stack.

For example:

void func()
{
    int i = 0; // Every time `func` is called, '0' is loaded into the stack
    ...
}

This is something that you might want to avoid, in particularly since the C and C++ languages are also designated for real-time systems, where every operation matters.

And by the way, when you declare MyClass myInstance, you can indeed rest assure that the default constructor is called, but you can choose whether or not you want to do anything in that constructor.

So the C and C++ languages allow you to make the same choice for primitive-type variables as well.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top