Deep comparison of unique_ptr in std :: set when using the == operator

I am trying to use std::set to store a unique_ptr set for a custom object that I defined. I provide a custom comparison function when defining a set (to provide a deep comparison). This comparison function seems to work correctly by inserting elements into a set. Items with equivalent content are not inserted twice.

However, if I compare two sets using operator== , it seems to be ignored, i.e. sets with equivalent elements are returned as not equal, while I expect (would like) to be equal (since the user comparison function I am providing makes a deep comparison).

Is the comparison function used only during insertion? If so, is there an alternative to getting operator== for a deep comparison?

Any pointers appreciated. Thanks:)

Code example

 // // 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; } 
+6
source share
1 answer

C ++ 11 container requirements say a == b equivalent

 distance(a.begin(), a.end()) == distance(b.begin(), b.end()) && equal(a.begin(), a.end(), b.begin()) 

and std::equal does not use your own comparison, it uses operator==

You can do the comparison yourself by calling std::equal using a special predicate:

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

In C ++ 14, this is simpler because the new std::equal overload accepts four iterators, although, as TemplateRex points out in the comment below, it is less efficient than a.size() == b.size() testing 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); }); 

In C ++ 14, you can save some typing using polymorphic 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); }); 
+7
source

Source: https://habr.com/ru/post/974481/


All Articles