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

时间:2014-04-08 15:06:09

标签: c++ sorting c++11 stl

当类属性可变时,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;
    });
}

但是,当不可变时,同一个类与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;
    });
}

谁能告诉我为什么?

非常感谢。

1 个答案:

答案 0 :(得分:5)

C ++的std::sort要求被排序的迭代器实现ValueSwappable

  

如果

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

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

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

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

  

说明:

     
      
  • tT类型的可修改左值。
  •   
  • rvT类型的右值表达式。
  •   
     

要求:

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

您的编译器似乎已损坏......

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

您的不可变对象不应满足此要求(因为它是不可变的)......

话虽这么说,你的operator=重载会导致编译器崩溃,因为你通过引用返回一个堆栈变量。

operator=重载几乎总是通过引用返回*this。这需要改变对象。所以它在一个不可变的对象中没有多大意义。

您真的需要对这些对象进行排序吗?

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

  1. 您可以对指针矢量进行排序。
  2. 您可以对std ::不可变对象列表进行排序。
  3. 还有其他选择..
  4. 此代码的最小(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);
    }