Home > database >  C `std::set_difference` with different output for different compilers
C `std::set_difference` with different output for different compilers

Time:05-23

Now, I have code below which just tests the std::set_difference in the standard library:

#include <algorithm>
#include <vector>
#include <memory>
#include <iostream>

struct Node{
    public:
        Node(int x) : foo(x){}
    int foo = 10;
};

using NodePtrVec = std::vector<std::shared_ptr<Node>>;
using NodePtr = std::shared_ptr<Node>;
using IntVec = std::vector<int>;
int main(void){

    // pointer test
    NodePtr inA_1 = std::make_shared<Node>(1);
    NodePtr inA_2 = std::make_shared<Node>(11);
    NodePtr inA_3 = std::make_shared<Node>(111);

    NodePtr inB_1 = std::make_shared<Node>(2);
    NodePtr inB_2 = std::make_shared<Node>(22);
    NodePtr inB_3 = std::make_shared<Node>(222);

    NodePtr both_1 = std::make_shared<Node>(3);
    NodePtr both_2 = std::make_shared<Node>(33);


    NodePtrVec a{inA_1,inA_2,inA_3,both_1,both_2};
    NodePtrVec b{inB_1,inB_2,inB_3,both_1,both_2};
    NodePtrVec c{};
    std::set_difference(a.begin(), a.end(), b.begin(), b.end(),
                        std::back_inserter(c));

    for(const auto& tmp : c){
        std::cout << tmp->foo << std::endl;
    }
    // int test
    std::cout << "int test" << std::endl;
    IntVec int_a = {1,5,4,2,3};
    IntVec int_b = {1,10,7};
    IntVec int_c;
    std::set_difference(int_a.begin(), int_a.end(), int_b.begin(), int_b.end(),
                        std::back_inserter(int_c));

    for(const auto& tmp : int_c){
        std::cout << tmp << std::endl;
    }
}

When I compile this with Clang/GCC, I got outputs:

ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
1
11
111
int test
5
4
2
3

UPDATE the source code case I want to actually use (suppose Node are some actions I will do. So these actions will happen in the order of total):

#include <algorithm>
#include <vector>
#include <memory>
#include <iostream>

struct Node{
    public:
        Node(int x) : foo(x){}
    int foo = 10;
};

using NodePtrVec = std::vector<std::shared_ptr<Node>>;
using NodePtr = std::shared_ptr<Node>;
using IntVec = std::vector<int>;
int main(void){

    // pointer test
    NodePtr inA_1 = std::make_shared<Node>(1);
    NodePtr inA_2 = std::make_shared<Node>(11);
    NodePtr inA_3 = std::make_shared<Node>(111);

    // total elements
    NodePtrVec total{inA_1,inA_2,inA_3};
    // sub set of the elements
    NodePtrVec sub{inA_2};
    NodePtrVec c{};
    // just want to get the compliment of the sub in total
    // as expected, c should be {inA_1,inA_3}
    std::set_difference(total.begin(), total.end(), sub.begin(), sub.end(),
                        std::back_inserter(c));

    for(const auto& tmp : c){
        std::cout << tmp->foo << std::endl;
    }
}

OK, this seems good and it actually correspond to the std::set_difference., check the link:https://godbolt.org/z/MnvbKE97e But when I choose MSVC, I got different outputs (check the link: https://godbolt.org/z/nYre1Eono):

example.cpp
ASM generation compiler returned: 0
example.cpp
Execution build compiler returned: 0
Program returned: 0
1
11
111
3
33
int test
5
4
2
3

oops, we got unexpected results! By the way, It seems outputs will change when I changed the MSVC compiler version. But Why?

CodePudding user response:

The ranges input to set_difference have to be sorted. Yours are not sorted.

CodePudding user response:

Like mentioned in the comments, in your case std::set_difference is comparing shared_ptr, not the values your pointers are pointing to. It could still work of course, because std::shared_ptr has operator== that just compares the addresses of raw pointers, however the requirement of set_difference is that your ranges are sorted, which is not the case if you look at the output of MSVC (looks like clang by chance allocated memory in ascending order, which resulted in sorted vectors). Sort your vectors first:

std::sort(a.begin(), a.end());
std::sort(b.begin(), b.end());

and you will get your desired output also with MSVC. Or even better, sort your vectors using custom comparator, and then calculate the set difference using custom comparator, which will be more idiomatic:

std::sort(a.begin(), a.end(), [](auto lhs, auto rhs) { return lhs->foo < rhs->foo; });
std::sort(b.begin(), b.end(), [](auto lhs, auto rhs) { return lhs->foo < rhs->foo; });
std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(c), [](auto lhs, auto rhs) {
    return lhs->foo < rhs->foo;
});

EDIT

I just read in the comments that you actually want to compare the pointers, not the values they point to. In this case, first part of my answer is the most relevant.

  • Related