使用常量迭代器对唯一指针的向量进行排序

时间:2017-12-13 14:21:46

标签: c++ sorting vector unique-ptr const-iterator

我的问题是为什么我可以用开头/结尾排序一个唯一指针的向量,但不能用cbegin / cend排序

编译:

std::sort(teachers.begin(), teachers.end(), compare_by_uniqptr);

但由于某种原因,这给了我一个C2280试图引用已删除的功能。

std::sort(teachers.cbegin(), teachers.cend(), compare_by_uniqptr);

以下是一些背景信息。 '教师'是教师对象的唯一指针的向量。

class Teacher : public Person {
private:
  std::vector<std::unique_ptr<Student>> students;
public:
  Teacher(std::string name) : Person(name) {}
  void insert(std::string name);
  int num_students() { return students.size(); }
};

std::vector<std::unique_ptr<Teacher>> teachers;

bool compare_by_uniqptr(const std::unique_ptr<Teacher>& a,
                        const std::unique_ptr<Teacher>& b) 
{
  return a.get()->num_students() > b.get()->num_students();
}

我按照每个学生按降序排列的学生数量对它们进行排序。开始/结束编译但cbegin / cend没有编译。为什么呢?

4 个答案:

答案 0 :(得分:2)

因为std::sort通过移动来对范围内的元素进行排序。这意味着元素将通过迭代器进行修改;它不适用于const的迭代器。

答案 1 :(得分:2)

无法复制唯一指针(否则它们将失去其唯一性)。出于这个原因,当它们被排序时,它们将需要移动(或交换)。这些操作需要更改唯一指针的 internals 。当然,你不能通过const引用来改变对象的内部。

答案 2 :(得分:1)

为什么cbegin()cend()不起作用? documentation中所述的std::sort()具有以下类型要求:

  

-RandomIt必须满足ValueSwappable和RandomAccessIterator的要求。

     

- 取消引用的RandomIt类型必须符合MoveAssignable和MoveConstructible 的要求。

     

- 比较必须符合比较的要求。

重点是我的。所以std::vector::const_iterator不满足这些要求。所以,即使你有std::vector<int>并尝试使用它们也无效。如果您使用begin()end() / std::unique_ptr上询问原因,那么您也可以在documentation中看到它:

  

std :: swap(std :: unique_ptr)(C ++ 11)专门研究std :: swap算法   (功能模板)

因此std::unique_ptr值满足ValueSwappable概念。

答案 3 :(得分:0)

这是一个解决方案。兼容到c ++ 11:

#include <vector>
#include <string>
#include <memory>
#include <algorithm>

struct Person {
    Person(std::string name);
};

struct Student : Person {

};

class Teacher : public Person {
private:
  std::vector<std::unique_ptr<Student>> students;
public:
  Teacher(std::string name) : Person(name) {}
  void insert(std::string name);
  int num_students() const { return students.size(); }
};

std::vector<std::unique_ptr<Teacher>> teachers;

struct by_num_students
{
    bool operator()(Teacher const& l, Teacher const& r) const
    {
        return l.num_students() < r.num_students();
    }
};

template<class Comp>
struct by_pointee_impl
{
    template<class L, class R>
    bool operator()(L&& l, R&& r) const 
    {
        return comp(*l, *r);
    }

    Comp comp;
};
template<class Comp>
auto by_pointee(Comp comp) -> by_pointee_impl<Comp>
{
    return by_pointee_impl<Comp>{comp};
};

int main()
{
    std::sort(begin(teachers), end(teachers), by_pointee(by_num_students()));
}