2014-08-28 42 views
6

我想用std::set将一组unique_ptr保存到我已定义的自定义对象中。我在定义集时提供自定义比较函数(以启用深度比较)。在将元素插入到集合中时,此比较函数似乎可以正常工作,即具有等同内容的项目不会插入两次。但是,如果我使用operator==来比较两个集合,它似乎被忽略,即具有等价元素的集合被返回为不相等,而我期望(愿意)它是相等的(因为我提供的自定义比较函数做了深入的比较)。使用运算符时std :: set中unique_ptr的深度比较==

仅在插入过程中使用比较函数吗?如果是这样,有没有其他办法可以让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; 
} 
+0

@BartoszKP,绝对没有重复,这个问题是关于'的std ::设置'它不使用自定义比较函数,所以'operator =='没有问题。这里情况不同。 – 2014-08-28 13:59:14

回答

7

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

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

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

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

在C++ 14可以使用多态的λ节省一些打字:

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

谢谢。我在我的项目中使用了C++ 14,并且上面的代码工作正常:) – georgemp 2014-08-28 15:11:08

+2

IIRC,两条双向迭代器(线性)对4段'std :: equal'调用'std :: distance',而设定的大小可以在一段时间内获得。那么3段过载不会在设置的元素上保存指针追踪路径吗? – TemplateRex 2014-08-29 08:54:37

+0

@TemplateRex,是的,这是一个很好的观点。编辑。 – 2014-08-29 09:45:18