0

In the below code, I expect members of a being inited with gargabe as they are not mentioned in the members-init-list of the called constructor (with two int parameters). Instead, I'm constantly getting 0 in both i and j of a, b and c and I am failing to see why. Could anybody please point me in the right direction?

#include <iostream>
#include <type_traits>


class A {
    public:
        int i;
        int j;
        A() = delete;
        A(int a, int b) { std::cout << "VOLOLO!" << std::endl; };
};

int
smear_stack(int p)
{
    int j = p++;
    int a[500] = {};
    for(int i = 0; i < 499; i++) {
        a[i] = ++j;
    }
    std::cout << j << std::endl;
    return ++j;
}

int main(void)
{
    int i = 2;
    i = smear_stack(++i);

    A a  (i, 32 );
    std::cout << "a is " << a.i << " " << a.j << std::endl;

    A b = { a };
    std::cout << "b is " << b.i << " " << b.j << std::endl;

    A c = { a.i, a.j };
    std::cout << "c is " << c.i << " " << c.j << std::endl;
}
Anton Tretyakov
  • 303
  • 1
  • 9
  • 2
    [Try it with a different compiler](https://wandbox.org/permlink/i9RG5pFQqHIUHdIG) (or perhaps, optimisation level). And turn optimisation on and you'll get a bunch of compiler warnings. You can't rely on uninitialised variables to contain _any_ particular value, that's just not how things work. – Paul Sanders Jul 01 '22 at 19:58
  • 2
    All of this is not legal code, but in practice, you are smearing the stack below the current stack frame. The space for `a`, `b`, and `c` is probably reserved on entry to the function, so the call to `smear_stack` doesn't affect them. – user3188445 Jul 01 '22 at 21:48
  • @PaulSanders hey, thanks for the answer! So, accessing an indeterminate value is UB, so i cannot reason about what is going on? In my tests with wandbox that were only `c` members being all 0 with multiple versions of compilers. – Anton Tretyakov Jul 01 '22 at 22:33
  • @user3188445 thanks for pointing the thing about frame, that one eluded me. I tried to call it from other functions with no avail to change the contents, but I guess UB is UB) – Anton Tretyakov Jul 01 '22 at 22:38
  • 1
    @AntonTretyakov Not really, no, there's not really any point. – Paul Sanders Jul 01 '22 at 22:44

1 Answers1

1

The i and j fields that you are accessing are, indeed, uninitialized. However, you are smearing the wrong part of the stack. It just so happens that on most OSes, the stack is initially all zeros. It even used to be common in C (long ago) to assume that automatic variables in main were zero-initialized.

To see that the memory is indeed uninitialized, it suffices to put something else there. Here's an example:

#include <iostream>
#include <memory>

class A {
public:
    int i;
    int j;
    A() = delete;
    A(int a, int b) { std::cout << "VOLOLO!" << std::endl; };
};

union U {
    int is[2];
    A a;
    U() : is{3,4} {}
};

int
main()
{
    U u;
    std::construct_at(&u.a, 5, 6);
    std::cout << u.a.i << ", " << u.a.j << std::endl;
    // output:
    // VOLOLO!
    // 3, 4
}
user3188445
  • 4,062
  • 16
  • 26