为什么STL的std :: sort不能用于不可变类?

use*_*838 1 c++ sorting stl c++11

当类属性是可变的时,Std :: sort有效.例如,以下代码有效,矢量按预期按升序排序.

class PersonMutable
{
public:

    PersonMutable(int age, std::string name):
        Age(age),Name(name)
    {
    }



    int Age;
    std::string Name;
};



void TestSort()
{
    std::vector<PersonMutable> people;
    people.push_back(PersonMutable(24,"Kerry"));
    people.push_back(PersonMutable(30,"Brian"));
    people.push_back(PersonMutable(3,"James"));
    people.push_back(PersonMutable(28,"Paul"));

    std::sort(people.begin(),people.end(),
        [](const PersonMutable& a, PersonMutable & b) -> bool
    {
        return a.Age < b.Age;
    });
}
Run Code Online (Sandbox Code Playgroud)

但是,当使用不可变时,同一个类与std :: sort不兼容.

class PersonImmutable
{
public:

    PersonImmutable(int age, std::string name):
        Age(age),Name(name)
    {
    }

    PersonImmutable& operator=(const PersonImmutable& a)
    {
        PersonImmutable b(a.Age,a.Name);
        return b;
    }

    const int Age;
    const std::string Name;
};


void TestSort()
{
    std::vector<PersonImmutable> people;
    people.push_back(PersonImmutable(24,"Kerry"));
    people.push_back(PersonImmutable(30,"Brian"));
    people.push_back(PersonImmutable(3,"James"));
    people.push_back(PersonImmutable(28,"Paul"));

    std::sort(people.begin(),people.end(),
        [](const PersonImmutable& a, PersonImmutable & b) -> bool
    {
        return a.Age < b.Age;
    });
}
Run Code Online (Sandbox Code Playgroud)

谁能告诉我为什么?

非常感谢.

Bil*_*nch 5

C++ std::sort需要对迭代器进行排序ValueSwappable.

如果是,则类型T是ValueSwappable

  1. 类型T满足迭代器要求
  2. 对于任何类型为T的dereferencable对象x(即除了结束迭代器之外的任何值),*x满足Swappable要求.

并且可以交换,你基本上需要这个工作:

using std::swap;
swap(*x, *y);
Run Code Online (Sandbox Code Playgroud)

此外,std::sort要求以下表达式有效(MoveConstructibleMoveAssignable:

定义:

  • t是一个可修改的左值类型T.
  • rv是类型的右值表达式T.

要求:

  1. t = rv;
  2. T u = rv;
  3. T(rv);

你的编译器似乎坏了......

您提供的代码确实符合这些要求.所以我不确定为什么你的编译器拒绝这个代码.由于过载,您PersonImmutable确实实现了要求.std::swapoperator=

你的不可变对象不应该满足这个要求(因为它是不可变的)......

话虽如此,您的operator=重载将导致编译器崩溃,因为您通过引用返回堆栈变量.

一个operator=超载应该总是返回*this引用.这需要改变对象.所以它在一个不可变的对象中没有多大意义.

你真的需要对这些物体进行排序吗?

如果你必须对它们进行排序,有一些选择.

  1. 您可以对指针矢量进行排序.
  2. 您可以对std ::不可变对象列表进行排序.
  3. 还有其他选择......

这段代码的最小(ish)测试用例......

有效的编译器应接受以下代码作为有效.听起来你的不是.

#include <string>

class PersonImmutable {
    public:
        PersonImmutable(int age): Age(age) {}

        PersonImmutable operator=(const PersonImmutable& a) {
            return *this;
        }

    private:
        const int Age;
};

int main() {
    PersonImmutable a(1, "a");
    PersonImmutable b(2, "b");

    using std::swap;
    swap(a,b);
}
Run Code Online (Sandbox Code Playgroud)