使用 std::sort 对自定义类的智能指针进行排序

Sorting smartpointer of custom classes with std::sort

本文关键字:指针 智能 排序 std sort 自定义 使用      更新时间:2023-10-16

我遇到的问题是我有一个实现operator<的自定义类的shared_ptr向量。

在堆栈上使用类时,我可以使用 std::sort,而无需指定Compare作为排序参数。但是,当然,当我使用shared_ptr时(显然我认为)会尝试对指针进行排序,而不是对象本身。

我想知道是否可以在带有智能指针的容器上调用std::sort,并且仍然可以调用实际对象的 Compare 运算符而不是指针,而无需提供第三个参数来"排序"。

为完整起见,MWE:

#include <vector>
#include <iostream>
#include <algorithm>
#include <memory>
class Date
{
public:
    Date(int y, int m) : year(y), month(m) {}
    bool operator<(const Date& rhs)
    {
        if (year > rhs.year) return false;
        else if (year == rhs.year)
        {
            return month < rhs.month;
        }
        return true;
    }
    int year;
    int month;
};
int main()
{
    Date d1(1999,12);
    Date d3(2000,10);
    Date d2(2000,1);
    Date d4(1997,9);
    std::vector<std::shared_ptr<Date>> dates = {std::make_shared<Date>(d1), std::make_shared<Date>(d2), std::make_shared<Date>(d3), std::make_shared<Date>(d4)};
    std::sort(dates.begin(), dates.end()); // doesn't work. orders by pointers
    // std::sort(dates.begin(), dates.end(), [](std::shared_ptr<Date> d1, std::shared_ptr<Date> d2) { return *d1 < *d2; }); // this works
    for (const auto& d : dates)
    {
        std::cout << d->year << " " << d->month << 'n';
    }
    return 0;
}

正如你所发现的,std::shared_ptr的比较运算符使用它引用的指针。这样,2 个分配的实例比较相等,仍然比较为不相等。

使用函数显式排序是一件好事。

std::sort(dates.begin(), dates.end(), [](std::shared_ptr<Date> d1, std::shared_ptr<Date> d2) { return *d1 < *d2; });

但是,如果你必须在多个地方这样做,你可以将ptr包装在一个类/结构中:

template<typename T>
struct SharedPtr final
 {
       std::shared_ptr<T> ptr;
       bool operator==(const T &rhs) const
        { return *ptr == rhs; }
       bool operator==(const SharedPtr<T> &rhs) const
        { return *ptr == *rhs.ptr; }
      // ...
 };

随意使用 nullptr 检查、其他重载和运算符进行扩展<</p>

在您的情况下,需要提供第三个参数。但是,如果您要大量使用它,则可以通过创建一个重载的特殊结构来简化它operator()

class Date
{
public:
    struct CompareSharedPtr
    {
        bool operator()(const std::shared_ptr<Date>& d1, const std::shared_ptr<Date>& d2)
        {
            return *d1 < *d2;
        }
    };
    Date(int y, int m) : year(y), month(m) {}
    bool operator<(const Date& rhs)
    {
        if (year > rhs.year) return false;
        else if (year == rhs.year)
        {
            return month < rhs.month;
        }
        return true;
    }
    int year;
    int month;
};

和用法

std::sort(dates.begin(), dates.end(), Date::CompareSharedPtr{});