【问题标题】:Sorting vector of unique pointers唯一指针的排序向量
【发布时间】:2026-01-17 18:40:01
【问题描述】:

您好,我是 C++ 新手,在尝试对唯一指针向量进行排序时遇到了困难。我有一个基类和派生类(这里是一个)。

class Item
{
public:
    virtual void printData() {}
};

class IntItem : public Item
{

public:
    int data;
    IntItem(int data)
    {
        this->data = data;
    }
    void printData()
    {
        std::cout << data;
    }
};
struct intItemCompare
{
    inline bool operator()(std::unique_ptr<IntItem>& a, std::unique_ptr<IntItem>& b)
    {
        return a->data < b->data;
    }
};

我有std::vector&lt;std::unique_ptr&lt;Item&gt;&gt; data;,其中存储了派生类对象的唯一指针 - 不是 Item 类(例如 IntItem 对象)

数据像这样被推送到向量:

std::unique_ptr<IntItem> newItem= std::make_unique<IntItem>(10); // 10 is just random number
data.push_back(std::move(newItem));

我想用std::sort(data.begin(),data.end(),intItemCompare());对其进行排序 其中一个错误是
no known conversion for argument 1 from ‘std::unique_ptr&lt;Item&gt;’ to ‘std::unique_ptr&lt;IntItem&gt;&amp;’ 41 | inline bool operator()(std::unique_ptr&lt;IntItem&gt;&amp; a, std::unique_ptr&lt;IntItem&gt;&amp; b)

如果需要,我可以添加整个错误消息。

我应该如何实现它?我做错了吗?感谢您的帮助。

【问题讨论】:

  • 您应该显示data 的声明。请阅读minimal reproducible example
  • A std::unique_ptr&lt;Item&gt;std::unique_ptr&lt;IntItem&gt; 的类型不同,即使 IntItem 派生自 Item
  • 如果你有一个Items 而不是intItems 的容器,对它们进行排序是否有意义?如果该容器中有stringItems 怎么办?你如何对一个整数排序一个字符串?
  • @FrançoisAndrieux 你所说的声明是什么意思?项目如何推送到数据的信息还不够吗?
  • @Riomare std::sort 不知道向量的元素指向什么样的Item,它只能假设那些指向的对象是从Item 派生的。它要求您的比较器接受指向 Item 的指针,而不是指向某些派生类型的指针。

标签: c++ algorithm polymorphism unique-ptr


【解决方案1】:

我会在您的代码中更改一些内容:

  • 如果你想多态处理你的项目,你应该创建派生类的堆实例,例如IntItem,但随后使用指向基类的指针向量 Item
  • 为了根据项目的数据对项目进行排序,您可以提供一个虚拟方法getData()
  • 我绝对不会在比较函数中使用unique_ptrs,而只是使用原始指针; std::ranges 投影在这里很合适,因为您可以告诉 sort 首先获取指向每个元素的原始指针并将其传递给比较函数。

[Demo]

#include <algorithm>  // sort
#include <iostream>  // cout
#include <memory>  // make_unique, unique_ptr
#include <vector>

class Item
{
public:
    virtual int getData() = 0;
    virtual void printData() = 0;
};

class IntItem : public Item
{
private:
    int data;
public:
    explicit IntItem(int d) : data{d} {}
    int getData() { return data; }
    void printData() { std::cout << data; }
};

struct ItemCompare
{
    inline bool operator()(Item* a, Item* b)
    {
        return a->getData() < b->getData();
    }
};

int main()
{
    std::vector<std::unique_ptr<Item>> items{};
    for (auto&& i : { 10, -15, 40, 0, 100 })
    {
        std::unique_ptr<Item> newItem = std::make_unique<IntItem>(i);
        items.push_back(std::move(newItem));
    }
    std::ranges::sort(items, ItemCompare{},
                      [](auto& item_up) { return item_up.get(); });
    for (auto& i : items)
    {
        std::cout << i->getData() << " ";
    }
}

// Outputs
//
//   -15 0 10 40 100

现在,如果您想向Item 添加更多子类,例如StringItem,但能够对通用项目列表进行排序,您应该提供一些要排序的内容。下面的示例根据插入顺序对项目进行排序:

  • 使用静态计数器在 Item 构造函数中为项目分配一个 ID。
  • ItemCompare::operator() 按 ID 比较项目。

[Demo]

#include <algorithm>  // shuffle, sort
#include <iostream>  // cout
#include <memory>  // make_unique, unique_ptr
#include <random>  // default_random_engine, random_device
#include <string>
#include <vector>

class Item
{
private:
    static inline size_t current_id{};
    size_t id;
public:
    Item() : id{current_id++} {}
    size_t getId() { return id; }
    virtual void printData() = 0;
};

class IntItem : public Item
{
private:
    int data;
public:
    explicit IntItem(int d) : Item{}, data{d} {}
    void printData() { std::cout << data; }
};

class StringItem : public Item
{
private:
    std::string data;
public:
    explicit StringItem(const std::string& d) : Item{}, data{d} {}
    void printData() { std::cout << data; }
};

struct ItemCompare
{
    inline bool operator()(Item* a, Item* b) { return a->getId() < b->getId(); }
};

int main()
{
    std::vector<std::unique_ptr<Item>> items{};
    for (auto&& i : { 10, -15, 40 })
    {
        std::unique_ptr<Item> newItem = std::make_unique<IntItem>(i);
        items.push_back(std::move(newItem));
    }
    for (auto&& i : { "blah", "foo", "meh" })
    {
        std::unique_ptr<Item> newItem = std::make_unique<StringItem>(i);
        items.push_back(std::move(newItem));
    }

    std::ranges::shuffle(items, std::default_random_engine{ std::random_device{}()});
    std::cout << "After shuffling... ";
    for (auto& item_up : items) { item_up->printData(); std::cout << " "; }
    std::cout << "\n";

    std::ranges::sort(items, ItemCompare{},
                      [](auto& item_up) { return item_up.get(); });
    std::cout << "After sorting... ";
    for (auto& item_up : items) { item_up->printData(); std::cout << " "; }
    std::cout << "\n";
}

// Outputs:
//
//   After shuffling... -15 foo meh 40 blah 10 
//   After sorting... 10 -15 40 blah foo meh 

【讨论】:

    最近更新 更多