c++ ' std::set_difference '在不同的编译器中有不同的输出



现在,下面的代码只测试标准库中的std::set_difference:

#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;
}
}

当我用Clang/GCC编译它时,我得到了输出:

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

我想实际使用的源代码案例(假设Node是我将要执行的一些操作)。所以这些动作将按照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;
}
}

好的,这看起来不错,它实际上对应于std::set_difference。,请查看链接:https://godbolt.org/z/MnvbKE97e但是当我选择MSVC时,我得到了不同的输出(检查链接: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

哎呀,我们得到了意想不到的结果!顺便说一句,当我改变MSVC编译器版本时,输出似乎会改变。但是为什么呢?

输入到set_difference的范围必须排序。你的没有排序。

就像评论中提到的那样,在您的情况下,std::set_difference比较的是shared_ptr,而不是您的指针指向的值。当然,它仍然可以工作,因为std::shared_ptroperator==,它只是比较原始指针的地址,但是set_difference的要求是您的范围是排序的,如果您查看MSVC的输出,情况就不是这样了(看起来像clang偶然按升序分配内存,这导致向量排序)。先对矢量进行排序:

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

,您也将使用MSVC获得所需的输出。或者更好的是,使用自定义比较器对向量进行排序,然后使用自定义比较器计算集合差,这将更习惯:

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;
});

编辑我刚刚在注释中看到,你实际上是想比较指针,而不是它们指向的值。在这种情况下,我回答的第一部分是最相关的。

EDIT2:

所以这些动作将按照total

的顺序发生

那么你要么复制你的向量,排序,并计算差异,或者你不能在你的情况下使用std::set_difference。如果你的操作的相对顺序需要保留,也许可以尝试这样做:迭代A和插入元素到C,如果它不存在于B中。因为只有在A中的元素的顺序需要保留,使用std::unordered_set为您的容器B,因为它有恒定的时间查找(平均):

NodePtrVec total{inA_1,inA_2,inA_3};
std::unordered_set<NodePtr> sub{inA_2};
NodePtrVec c{};
for (auto el : total)
{
if (sub.count(el) == 0)
{
c.push_back(el);
}
}

最新更新