Self-Referring Structs--How Is This Possible?

Say we have a piece of code like this:
1
2
3
4
struct foo {
	int val = 123;
	foo *bar; //Pointer to another foo
};

But how does this pass compilation?? Doesn't this create an infinite loop of foos? And why does the above code work while this doesn't:
1
2
3
4
struct foo {
	int val = 123;
	foo bar;
};


And if I try to do this:
1
2
3
4
5
6
foo f;
cout << f.val << endl;
cout << f.bar->val << endl;
cout << f.bar->bar->val << endl;
cout << f.bar->bar->bar->val << endl;
//... and so on 

It passes compilation, but upon reaching this line:
 
cout << f.bar->val << endl;

This is what happened:
1
2
3
4
5
Exception thrown: read access violation.

f.bar was 0xCCCCCCCC.

If there is a handler for this exception, the program may be safely continued.


This all got me so confused. If trying to read f.bar causes an exception, why does this pass the compilation at all?? And, is there any way we can access f.bar without causing an exception to be thrown (and are these self-referring structs used in C++ at all)?
Last edited on
If trying to read f.bar causes an exception, why does this pass the compilation at all??
The set of syntactically valid programs is a strict superset of the set of well-formed programs. In other words, the compiler may accept programs that crash or otherwise perform illegal operations.

And, is there any way we can access f.bar without causing an exception to be thrown
For example,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Initialize
foo *head = nullptr;

//Populate
while (true){
    int n;
    std::cout << "Enter next number (0 to stop): ";
    std::cin >> n;
    if (!n)
        break;
    foo *node = new foo;
    node->val = n;
    node->bar = head;
    head = node;
}

//Display
for (foo *node = head; node; node = node->bar)
    std::cout << node->bar;

//Clean up
while (head){
    foo *node = head;
    head = head->bar;
    delete node;
}

and are these self-referring structs used in C++ at all
Sometimes. My example above is an ad-hoc linked list implementation. std::list does something similar internally. A type that contains pointers to itself is generally useful to build graph structures (lists, trees, etc.).
Last edited on
But how does this pass compilation?? Doesn't this create an infinite loop of foos? And why does the above code work while this doesn't:

When creating an object the compiler needs to know its size. The size of a struct depends on the sizes of its members.

Your first struct has two members: an int (integer type has known size) and a pointer (size of pointer is known too). There is no recursion. It is thus easy to calculate the size of stuct foo.

The second attempt contains an int and foo. The size of that member foo includes the size of int and foo. The size of that member foo of member foo includes the size of int and foo, and so on ... an infinite recursion.

It passes compilation, but upon reaching this line:

You have not set the pointer to point to a valid foo object. You are dereferencing an uninitialized pointer.

Always initialize pointer with nullptr or valid address. Then you can test the pointer has valid address before you dereference it.
Topic archived. No new replies allowed.