繁体   English   中英

C++ `std::set_difference` 对于不同的编译器具有不同的输出

[英]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_ptroperator==只是比较原始指针的地址,但是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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM