0

While making a small parser for a project, I kept getting Segmentation Faults... tracked it down to a transposition typo.

This code sample is NOT the original code but reproduces the fault.

I was surprised that none of my compilers spotted that the reference is uninitialized.

Both GCC and Clang appear to compile it without warning or error.

Shouldn't they be flagging the REFERENCE TO v2 as uninitialized?

I'm relatively new to C++ and am learning C++17/20. But I am curious as to why, in this case, the compilers aren't spotting that v2 is undefined but passing a reference to an undefined object anyhow.

#include <iostream>
#include <vector>
struct A
{
    using vectorA = std::vector<A>;
    int     foo;
    vectorA vA;

    A() = delete; // Implicit but let's be certain!

    A(int f) noexcept
        : foo {f},
          vA  {}
    {}
};

A::vectorA& recurse(A::vectorA& head, int tail) noexcept
{head.emplace_back(tail); return head;}

int main()
{
    // A tree of A's
    A::vectorA v1 {};

    // Fill it using recursive fn converting bars into foos,
    // a bar at a time
    int bar {666};
    A::vectorA v2 {recurse(v2, bar)};
    //                      ^
    // typo of 'v2' instead of 'v1' still compiles!
    // SHOULD, of course, read; A::vector_of_A v2 {recurse(v1, bar)};
    //
    // But v2 is... what exactly? At the point it is passed to recurse?
    // It is uninitialized although it has an address and (likely) space       
    // allocated to hold it.
    // No warning?

    std::cout << "Should this compile?\n";
    std::cout << "Oops! Segmentation Fault Guaranteed!\n";
}
David H Parry
  • 299
  • 3
  • 13
  • 2
    Related [Is passing a C++ object into its own constructor legal?](https://stackoverflow.com/q/32608458/1708801) and [Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++14?](https://stackoverflow.com/q/23415661/1708801) – Shafik Yaghmour Sep 19 '18 at 13:19
  • 2
    The standard dictates that a reference to a value is valid even before the value has been initialised. In the same way that a pointer to it is also valid. It's only invalid to access the variable through the reference prior to definition. Storing the reference for later use, for example, is a valid operation. – Richard Hodges Sep 19 '18 at 13:19
  • You're expecting a lot from the compiler. It would have to inspect `recurse`, see if it would be valid to give `v2` to it and then warn you if it isn't. The compiler isn't going to go through all that work. The syntax is correct so it is going to keep going. – NathanOliver Sep 19 '18 at 13:20
  • I know you can have an undefined reference... but passing it, I thought, was checked rigorously. – David H Parry Sep 19 '18 at 13:20
  • 1
    @DavidHParry But `v2` is a perfectly valid argument for the parameter `head`. If `recurse` was e.g. outputting `&head` instead of accessing the members of `head`, all would be well. – Angew is no longer proud of SO Sep 19 '18 at 13:22
  • Out of curiosity, how do you create an undefined reference (short of using an invalid numerical pointer value as "object" address)? (Your code here is not an example, as Angew and Richard have pointed out.) – Peter - Reinstate Monica Sep 19 '18 at 13:26
  • I should have said *uninitialized* instead of *undefined*. It was the **passing** of this reference that intrigued me as usually I get a warning/error. I know you can have reference that aren't specifically declared as referring to anything until, say, some constructor gets called. – David H Parry Sep 19 '18 at 13:33
  • 1
    If you use the "almost always auto" convention, then this `auto v2 = A::vectorA {recurse(v2, bar)};` would not compile. Not everyone buys into that style, so it depends on your team's druthers or your own style sensibilities. – Eljay Sep 19 '18 at 13:53

1 Answers1

6

If this would not compile then one could also not do the following, which is not too uncommon:

struct base {
    int& x;
    base(int& x) : x(x) {}
};

struct foo : base {
    int x;
    foo() : base(x) {}
};

At the time the base constructor is called, x is not yet initialized, yet it is completely valid to store a reference to it for later use.

This is just one example where getting a reference to a not yet initialized object is just fine and forbidding to do this would require to write very unclear cumbersome code.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • This is only a code snippet that reproduces the error made using CompilerExplorer and NOT the code that made the error... you'd need 20MB for that... – David H Parry Sep 19 '18 at 13:43
  • @DavidHParry sorry I dont get your comment. I am not refering to your code in my answer... "NOT the code that made the error" ? We can only discuss what we see here not something that only you have, if your example is substantially different from your real code you should edit the example – 463035818_is_not_an_ai Sep 19 '18 at 13:47
  • The fault that gave the error is stated above. You don't need the original code to understand the problem. The original had more instructive variable names than used here in this example? – David H Parry Sep 19 '18 at 13:52
  • @DavidHParray still dont get what you are trying to tell me. As I understood the question you ask whether passing an unitialized reference should be forbidden and I gave you an example where doing so is completely fine and forbidding to do so would be really bad. What has all this to do with "20MB needed to make the error" ? – 463035818_is_not_an_ai Sep 19 '18 at 13:54
  • @DavidHParry if you are disturbed by my critisism of your variable names, why not change them? Anyhow I'll remove the PS if that makes you feel better :P – 463035818_is_not_an_ai Sep 19 '18 at 13:56
  • Variable names changed to less cryptic ones? – David H Parry Sep 19 '18 at 14:02
  • @DavidHParry user463035818 is the most cryptic name i can think of – 463035818_is_not_an_ai Sep 19 '18 at 14:14
  • @DavidHParry not sure if you are trying to make fun of me or what. I would suggest you to got back to `v1` and `v2` and just forget the matter, because now your text in the question does not match the code – 463035818_is_not_an_ai Sep 19 '18 at 14:15