使用operator ==时std :: set中unique_ptr的深度比较

geo*_*emp 6 c++ c++11

我试图用std::set一组unique_ptr来定义我定义的自定义对象.我在定义集合时提供自定义比较功能(以启用深度比较).在将元素插入集合时,此比较函数似乎正常工作,即具有相同内容的项目未插入两次.

但是,如果我使用比较两个集合operator==,它似乎被忽略,即具有等效元素的集合返回不相等,而我期望(希望)它是相等的(因为我提供的自定义比较函数做了深度比较) .

比较功能是否仅在插入期间使用?如果是这样,是否可以选择进行operator==深入比较?

任何指针赞赏.谢谢 :)

示例代码

//
//  main.cpp
//  Test

#include <iostream>
#include <set>

class Person {
private:
    std::string mName;

public:
    Person(const std::string& name);
    virtual ~Person() {}

    void setName(std::string& name);
    std::string getName();
};

typedef std::unique_ptr<Person> PersonUniquePtr;

Person::Person(const std::string& name)
    : mName{ name }
{
}

void Person::setName(std::string& name)
{
    mName = name;
}   

std::string Person::getName()
{
    return mName;
}

bool isLess(Person* p1, Person* p2)
{
    if (p1->getName().compare(p2->getName()) == -1)
        return true;

    return false;
}

struct PersonUniquePtr_less {
    bool operator()(PersonUniquePtr const& p1, PersonUniquePtr const& p2) const
    {
        return isLess(p1.get(), p2.get());
    }
};

int main(int argc, const char* argv[])
{
    std::set<PersonUniquePtr, PersonUniquePtr_less> personSet1;
    std::set<PersonUniquePtr, PersonUniquePtr_less> personSet2;

    PersonUniquePtr person1 = std::make_unique<Person>("Adam");
    PersonUniquePtr person2 = std::make_unique<Person>("Adam");
    personSet1.insert(std::move(person1));
    personSet1.insert(std::move(person2));
    std::cout << "personSet1.size(): " << personSet1.size() << std::endl; //Expected 1

    PersonUniquePtr person3 = std::make_unique<Person>("Bruce");
    personSet1.insert(std::move(person3));
    std::cout << "personSet1.size(): " << personSet1.size() << std::endl; //Expected 2

    PersonUniquePtr person4 = std::make_unique<Person>("Adam");
    PersonUniquePtr person5 = std::make_unique<Person>("Bruce");
    personSet2.insert(std::move(person4));
    personSet2.insert(std::move(person5));
    std::cout << "personSet2.size(): " << personSet2.size() << std::endl; //Expected 2

    std::cout << "PersonSet1:" << std::endl;
    for (auto& person : personSet1) {
        std::cout << person->getName() << std::endl;
    } //Prints out Adam Bruce

    std::cout << "PersonSet2:" << std::endl;
    for (auto& person : personSet2) {
        std::cout << person->getName() << std::endl;
    } //Prints out Adam Bruce

    bool setsAreEqual = (personSet1 == personSet2);
    if (setsAreEqual) {
        std::cout << "Sets are equal" << std::endl;
    } else {
        std::cout << "Sets are not equal" << std::endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*ely 7

C++ 11容器要求a == b相当于

distance(a.begin(), a.end()) == distance(b.begin(), b.end())
&& equal(a.begin(), a.end(), b.begin())
Run Code Online (Sandbox Code Playgroud)

并且std::equal不使用您的自定义比较,它使用operator==

您可以std::equal使用自定义谓词调用自己执行比较:

a.size() == b.size()
&& std::equal(a.begin(), a.end(), b.begin(),
              [](PersonUniquePtr const& p1, PersonUniquePtr const& p2) {
                PersonUniquePtr_less cmp;
                return !cmp(p1, p2) && !cmp(p2, p1);
              });
Run Code Online (Sandbox Code Playgroud)

在C++ 14中它更简单,因为有一个新的重载std::equal需要四个迭代器,尽管正如TemplateRex在下面的注释中指出的那样,这比a.size() == b.size()手动测试效率低:

std::equal(a.begin(), a.end(), b.begin(), b.end(),
           [](PersonUniquePtr const& p1, PersonUniquePtr const& p2) {
             PersonUniquePtr_less cmp;
             return !cmp(p1, p2) && !cmp(p2, p1);
           });
Run Code Online (Sandbox Code Playgroud)

在C++ 14中,您可以使用多态lambda来保存一些输入:

std::equal(a.begin(), a.end(), b.begin(), b.end(),
           [](auto const& p1, auto const& p2) {
             PersonUniquePtr_less cmp;
             return !cmp(p1, p2) && !cmp(p2, p1);
           });
Run Code Online (Sandbox Code Playgroud)

  • IIRC,4脚`std :: equal`在两对双向迭代器(线性)上调用`std :: distance`,而设置大小在恒定时间内可用.那么3脚超载会不会在指定元素上保存指针追逐路径? (2认同)