Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Evaluation order in initialization

Tags:

In the following program:

#include <iostream>
struct I {
    int i;
    I(){i=2;}
    I(int _i){i=_i;}
};
int a[3] = {a[2] = 1};
int aa[3][3] = {aa[2][2] = 1};
I A[3] = {A[2].i = 1};
I AA[3][3] = {AA[2][2].i = 1};
int main(int argc, char **argv) {
    for (int b : a) std::cout << b << ' ';
    std::cout << '\n';
    for (auto &bb : aa) for (auto &b : bb) std::cout << b << ' ';
    std::cout << '\n';
    for (auto &B : A) std::cout << B.i << ' ';
    std::cout << '\n';
    for (auto &BB : AA) for (auto &B : BB) std::cout << B.i << ' ';
    std::cout << '\n';
    return 0;
}

The output is

1 0 0 
1 0 0 0 0 0 0 0 1 
1 2 2 
1 2 2 2 2 2 2 2 2

from http://ideone.com/1ueWdK with clang3.7

but the result is :

0 0 1 
1 0 0 0 0 0 0 0 1 
1 2 2 
1 2 2 2 2 2 2 2 2 

on http://rextester.com/l/cpp_online_compiler_clang also with clang 3.7.

On my own ubuntu, gcc 6.2 givs an internal compiler error on the construct int aa[3][3] = {aa[2][2] = 1}.

I'm assuming this is undefined behavior, but cannot find a definitive statement in the standard.

The question is:

Whether the evaluation order of the side effects on the assignment in the initializer list (e.g. a[2] = 1) and initialization of the actual element of the array (e.g. a[2]) defined in the standard?

It is explicitly stated as defined or undefined? Or does it become undefined just because it is not explicitly defined?

Or does the construct has defined or undefined behavior due to other reason aside from the evaluation order?

like image 754
fefe Avatar asked Nov 20 '16 03:11

fefe


People also ask

What is an evaluation order?

Order of evaluation refers to the operator precedence and associativity rules according to which mathematical expressions are evaluated.

What is the order of initialization for data?

In the initializer list, the order of execution takes place according to the order of declaration of member variables. While using the initializer list for a class in C++, the order of declaration of member variables affects the output of the program. Program 1: C++

What is the order of operand evaluation?

First, the left operand of * is evaluated; it produces the value 4. Then the right operand of * is evaluated. Since evaluation of the left operand set x to 4, evaluation of the right operand produces 4. Finally, the * operator itself is evaluated, producing the value 16.


1 Answers

Let's start with the simplest case:

I A[3] = {A[2].i = 1};
I AA[3][3] = {AA[2][2].i = 1};

Both of these are UB, due to a violation of [basic.life]. You are accessing the value of an object before its lifetime has begun. I does not have a trivial default constructor, and therefore cannot be vacuously initialized. Therefore, the object's lifetime only begins once a constructor has completed. The elements of the A array have not yet been constructed when you are accessing elements of that array.

Therefore, you are invoking UB by accessing a not-yet-constructed object.

Now, the other two cases are more complex:

int a[3] = {a[2] = 1};
int aa[3][3] = {aa[2][2] = 1};

See, int permits "vacuous initialization", as defined by [basic.life]/1. Storage for a and aa has been acquired. Therefore, int a[3] is a valid array of int objects, even though aggregate initialization has not yet begun. So accessing the object and even setting its state is not UB.

The order of operations here is fixed. Even pre-C++17, the initialization of the elements of the initializer list is sequenced before the aggregate initialization is invoked, as stated in [dcl.init.list]/4. Elements in the aggregate which are not listed in the initialization list here will be filled in as if by typename{} constructs. int{} means to value-initialize an int, which results in 0.

So even though you set a[2] and aa[2][2], they should immediately be overwritten via aggregate initialization.

Therefore, all of these compilers are wrong. The answer should be:

1 0 0 
1 0 0 0 0 0 0 0 0

Now granted, this is all very stupid and you shouldn't do it. But from a pure language perspective, this is well-defined behavior.

like image 144
Nicol Bolas Avatar answered Sep 26 '22 16:09

Nicol Bolas