0

Please note a variation of the classic singly-linked-list structure below:

#include <stdio.h>

struct Node;

struct SList {
    Node* root = nullptr;
};

struct Node {
    int* data = nullptr;
    SList* parent = nullptr;
    Node* next = nullptr;

    Node(Node const&) = delete;
    Node& operator=(Node const&) = delete;

    constexpr Node(int data, SList& list)
        : data(new int(data)), parent(&list), next(list.root) {
        list.root = this;
    }

    constexpr ~Node() {
        Node** p = &parent->root;
        while (*p != this) {
            p = &((*p)->next);
        }
        (*p) = this->next;
        delete data;
    }
};

constexpr int test() {
    SList list;

    Node n1(10, list);
    Node n2(20, list);
    Node n3(30, list);
    { Node n3_5(35, list); }
    auto pn4 = new Node(40, list);
    Node n5 = Node(50, list);
    delete pn4;

    int sum = 0;
    for (auto p = list.root; p; p = p->next) {
        sum += *p->data;
    }
    return sum;
}

int main() {
    auto constexpr retval = test();
    return retval;
}

There is a very subtle bug in there. If any of the references are const (like Node const n2(20, list);), we're storing a non-const pointer to a const object in the constructor of Node. This pointer is then used in the destructor of other other Node objects and cause undefined behavior. Making Node* next mutable is not an option because you can't use mutable fields in a constexpr function.

This structure is inherently not const-friendly. I either want to fix this code somehow, so it doesn't silently cause UB for all const instances, or disable creating const objects of type Node entirely (as a compile-time error). Since objects are not const in their constructor, I am not sure how one would do either of those.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93

0 Answers0