Std::set::find与Std::find在Std::set上使用const

std::set::find vs std::find on std::set with const

本文关键字:Std find set const      更新时间:2023-10-16

我写了一点(工作)测试代码,但我不明白为什么在test1函数中,我只能传递int* const作为参数,而在test2函数中,我可以传递const int*。如果我将const int*传递给test1,我会得到一个丢弃限定符错误。

在我的研究中,我发现std::findset::find都有一个const版本,所以我看不出为什么它们的行为不同。我也尝试了boost::container::flat_set而不是std::set,我得到了同样的结果。有人能解释一下吗?

class myClass
{
public:
    myClass() {};
    ~myClass() {};
    void add(int* ref)
    {
        this->_ref.insert(ref);
    };
    bool test1(int* const ref) const
    {
        return ( this->_ref.find(ref) != this->_ref.end() );
    }
    inline
    bool test2(const int* ref) const
    {
        return ( std::find(this->_ref.begin(), this->_ref.end(), ref) != this->_ref.end() );
    }
    std::set<int*> _ref;
};
int main()
{
    myClass test;
    test.add(new int(18));
    test.add(new int(35));
    test.add(new int(78));
    test.add(new int(156));
    std::cout<<test.test1(0)<<std::endl;
    std::cout<<test.test1(*test._ref.begin())<<std::endl;
    std::cout<<test.test2(0)<<std::endl;
    std::cout<<test.test2(*test._ref.begin())<<std::endl;
    return 0;
}

set::find()给出的答案是O(logN), std::find()给出的答案是O(N)。

同理,map::find()给出的答案是O(logN), std::find()给出的答案是O(N)。

容器std::set<int*>只有同构查找,因此您只能通过与相同类型的值进行比较来搜索键:find, count, erase。当然,const int*类型的值与int*类型不同,因此您的test2代码尝试将前者转换为后者,这是不允许的转换。

容器只能以这样的同构方式使用,这是c++从一开始就存在的一个缺点,更令人吃惊的不希望转换的例子是,当您有一个具有std::string键的映射,并且想要查找一个键作为字符串字面量提供的元素时。您总是必须构造动态std::string对象,即使std::string提供了带有字符串字面值的比较操作符。

因此,从c++ 14开始,您还可以通过拼写std::set<int*, std::less<>>来创建非同构查找的set(或map)。有了这样的容器,循环函数就变成了模板,您确实可以比较不同类型的值(将转换逻辑留给底层的< -操作符)。但是请注意,std::less<int*>需要在指针上提供严格的弱排序,而std::less<>没有,所以你可能会得到未定义的行为。