[英]C++ `std::set_difference` with different output for different compilers
现在,我有下面的代码,它只是测试标准库中的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_ptr
有operator==
只是比较原始指针的地址,但是set_difference的要求是你的范围是排序的,如果你查看 MSVC 的输出,情况并非如此(看起来像是偶然按升序分配的内存,这导致了排序的向量)。 首先对向量进行排序:
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;
});
编辑
我刚刚在评论中读到您实际上想要比较指针,而不是它们指向的值。 在这种情况下,我的答案的第一部分是最相关的。
编辑2:
所以这些动作会按照总的顺序发生
然后您必须复制您的向量,对其进行排序并计算差异,或者您不能在您的情况下使用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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.