Search code examples
c++set-difference

c++ list not resizing after set difference


Consider the following code:

#include <algorithm>
#include <iostream>
#include <list>

int main() {
    std::list<int> v = {1, 3, 4};
    std::cout << v.size() << std::endl;
    v.resize(0);
    std::cout << v.size() << std::endl;
}

after compiling the output, as expected, is

3
0

Now I add a set difference.

#include <algorithm>
#include <iostream>
#include <list>

int main() {
    std::list<int> x = {1, 3, 4};
    std::list<int> y = {1, 2, 3, 5};
    std::list<int> v;
    x.sort();
    y.sort();
    std::cout << v.size() << std::endl;
    auto it =
        std::set_difference(x.begin(), x.end(), y.begin(), y.end(), v.begin());
    std::cout << v.size() << std::endl;
    v.resize(0);
    std::cout << v.size() << std::endl;
}

and the output is

0
4
4

why does the resize work for the first example, but not in the second?


Solution

  • This is because it is undefined behavior.

    The last parameter to std::set_difference is an output iterator. You are passing in v.begin().

    This returns a pointer to the beginning of an empty list. In order for your intended code to work as advertised, the *iter++ operation of the output iterator must add new values to the list.

    Unfortunately, no matter what you do with the iterator that's returned by begin(), nothing that you do to it will make the list any bigger or smaller than it already is. It is just iterating over the existing contents of the list.

    At this point, you're pretty much in undefined behavior territory, and any results you get will be completely nonsensical (if not an immediate crash).

    Instead of passing in v.begin(), you need to use std::back_insert_iterator instead.