简体   繁体   English

为什么STL的std :: sort无法与不可变的类一起使用?

[英]Why does STL's std::sort not work with immutable classes?

Std::sort works when class properties are mutable. 当类属性可变时,Std :: sort起作用。 For example the following code works and the vector is sorted in ascending order as expected. 例如,以下代码有效,向量按预期升序排序。

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;
    });
}

But the same class when made immutable isn't compatible with std::sort. 但是,当同一类变为不可变时,它与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;
    });
}

Can anyone tell me why? 谁能告诉我为什么?

Many thanks. 非常感谢。

C++'s std::sort requires that the iterators being sorted implement ValueSwappable . C ++的std::sort要求std::sort的迭代器实现ValueSwappable

Type T is ValueSwappable if 如果T类型为ValueSwappable

  1. Type T satisfies the Iterator requirements T型满足迭代器要求
  2. For any dereferencable object x of type T (that is, any value other than the end iterator), *x satisfies the Swappable requirements. 对于T类型的任何可解除引用的对象x(即,除最终迭代器之外的任何值),* x都满足Swappable要求。

And to be swappable, you basically need this to work: 为了可交换,您基本上需要这样做:

using std::swap;
swap(*x, *y);

Additionally, std::sort requires the following expressions to be valid ( MoveConstructible and MoveAssignable : 此外, std::sort要求以下表达式有效( MoveConstructibleMoveAssignable

Definitions: 定义:

  • t is a modifiable lvalue of type T . t是类型T的可修改左值。
  • rv is an rvalue expression of type T . rv是类型T的右值表达式。

Requirements: 要求:

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

Your compiler appears to be broken... 您的编译器似乎坏了...

The code you have presented does meet these requirements. 您提供的代码确实符合这些要求。 So I'm not sure why your compiler is refusing this code. 因此,我不确定您的编译器为何拒绝此代码。 Your PersonImmutable does implement the requirements of std::swap because of the operator= overload. 由于operator=重载,您的PersonImmutable确实实现了std::swap的要求。

Your immutable object shouldn't meet this requirements though (because it's immutable)... 但是,您的不可变对象不应该满足此要求(因为它是不可变的)...

That being said, your operator= overload will cause the compiler to crash, because you're returning a stack variable by reference. 话虽如此,您的operator=重载将导致编译器崩溃,因为您要通过引用返回堆栈变量。

An operator= overload should almost always return *this by reference. operator=重载几乎应该总是通过引用返回*this Which requires mutating the object. 这需要变异对象。 So it doesn't make much sense in an immutable object. 因此,在一个不变的对象中并没有多大意义。

Do you really need to sort these objects? 您真的需要对这些对象进行排序吗?

If you have to sort them, there are some options. 如果必须对它们进行排序,则有一些选项。

  1. You can sort a vector of pointers. 您可以对指针向量进行排序。
  2. You can sort a std::list of immutable objects. 您可以对不可变对象的std :: list进行排序。
  3. There's other options too.. 还有其他选择。

The minimal(ish) testcase for this code... 此代码的最小(ish)测试用例...

A valid compiler should accept the following code as valid. 有效的编译器应接受以下代码为有效代码。 It sounds like yours does not. 听起来好像不是。

#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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM