类重载运算符 '<' 插入指向该对象集的共享指针时不调用

Class overloaded operator '<' is not called when inserting shared pointer to set of that objects

本文关键字:共享 指针 调用 对象 运算符 重载 lt 插入      更新时间:2023-10-16

考虑以下程序:

#include <string>
#include <iostream>
#include <set>
#include <memory>
class Boo
{
public:
using ShPtr = std::shared_ptr<Boo>;
bool operator < (const Boo& boo) const
{
std::cout << "Hello from operator";
return true;
}
};

int main(int, char*[])
{
std::set<std::shared_ptr<Boo>> _container;
_container.insert(Boo::ShPtr(new Boo()));
return 0;
}

根据std::set:的文档

在内部,集合容器保持其所有元素的排序如下由其比较对象指定的标准。这些元素是始终按照此顺序插入其相应位置。

所以我希望每次插入都调用comparation对象。

比较对象默认为:

template<typename _Key, typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<_Key> >
class set
{
...
}

在这种特殊情况下是:

template<typename _Sp>
struct _Sp_less : public binary_function<_Sp, _Sp, bool>
{
bool
operator()(const _Sp& __lhs, const _Sp& __rhs) const noexcept
{
typedef typename _Sp::element_type element_type;
return std::less<element_type*>()(__lhs.get(), __rhs.get());
}
};

这意味着比较是通过比较共享指针指向的对象来完成的。

我的问题是:为什么在我的程序运算符'<'Boo类对象的?

正如Richard Critten所注意到的:

@SombreroChicken"注意,shared_ptr的比较运算符只是比较指针值;实际指向的对象不会进行比较。"来源:en.cppreference.com/w/cpp/memory/shared_ptr/operator_cmp因此它编译干净,但只比较指针值

以下代码按预期工作:

#include <string>
#include <iostream>
#include <set>
#include <memory>
template<typename _Sp>
struct CompShPtrByObj : std::_Sp_less<_Sp>
{
bool
operator()(const _Sp& __lhs, const _Sp& __rhs) const noexcept
{
typedef typename _Sp::element_type element_type;
return std::less<element_type>()(*__lhs, *__rhs);
}
};
class Boo
{
public:
using ShPtr = std::shared_ptr<Boo>;
bool operator < (const Boo& boo) const
{
std::cout << "Hello form boo";
return true;
}
};

int main(int, char*[])
{
std::set<std::shared_ptr<Boo>, CompShPtrByObj<std::shared_ptr<Boo>>> _container;
Boo::ShPtr sharedBoo(new Boo());
Boo::ShPtr sharedBoo2(new Boo());
_container.insert(sharedBoo);
_container.insert(sharedBoo2);
std::set<std::shared_ptr<Boo>, CompShPtrByObj<std::shared_ptr<Boo>>>::iterator iter = _container.find(sharedBoo);
return 0;
}

但这个解决方案清楚吗?这种改变默认值的明显工作方式会误导任何使用该容器的人吗?