3
votes

When an element of a list is destroyed I want to iterate through the same list to see if it includes another specific element. This has to happen each time an element is removed.

It works fine if the container is a std::vector but it seem to iterate outside the for-loop and crash if its a std::list.

Is this undefined behavior?

(The following code example works in Visual Studio 2017 but stopped working in Visual Studio 2019)

#include <iostream>
#include <list>

class Element
{
public:
    Element(std::list<Element> &list) : list_(list) {}

    ~Element() {
        for (Element& e : list_)
        {
            std::cout << &e.list_ << std::endl;
        }
    }

    std::list<Element> &list_;
};

int main()
{
    std::list<Element> list = { Element(list), Element(list) };
    list.clear();
}
1
XY problem... each Element holding a reference to the list it assumes it is contained in looks like a terrible idea. For one, you can't really have any Element not contained in a list... What is the problem you are actually trying to solve? - DevSolar
This might be an interesting language-lawyer question. I wonder from which part of the C++ Standard (if any) implies that this code is illegal. - Daniel Langr
It is bit mysterious what I see. I can't find anything in the docs that it is not allowed to access a list while it is progressing clean itself. - Klaus

1 Answers

3
votes

This program has undefined behavior. In the declaration of the member variable list_, the type Element is an incomplete type, and you can't instantiate a std::list of an incomplete type. (So in some versions of a compiler, this may appear to work, but there is no guarantee that it will).

Since c++17, std::vector can be instantiated with an incomplete type, so long as the type satisfies the allocator completeness requirements, which I think Element does. So you can make list_ a std::vector<Element> if you want.