C++:为我的类型定义了我自己的赋值运算符,现在.sort()不适用于我的类型的向量?

Kev*_*vin 2 c++ sorting copy-constructor assignment-operator

我有一个类(那些已经读过Accelerated C++的人可能会发现这个类很熟悉)定义如下:

class Student_info{
public:
    Student_info() : midterm(0.0), final(0.0) {};
    Student_info(std::istream& is){read(is);};

    Student_info(const Student_info& s);

    ~Student_info();

    Student_info& operator=(const Student_info& s);

    //Getters, setters, and other member functions ommited for brevity

    static int assignCount;
    static int copyCount;
    static int destroyCount;

private:
    std::string name;
    double midterm;
    double final;
    double finalGrade;
    std::vector<double> homework;

};

typedef std::vector<Student_info> stuContainer;


bool compare(const Student_info& x, const Student_info& y);
Run Code Online (Sandbox Code Playgroud)

函数calculator()使用这种类型的对象.作为函数的一部分,使用库的通用排序函数对(已声明的)Student_info对象的向量进行排序.我的程序没有超过这一点(尽管根据NetBeans没有抛出任何异常并且程序正确退出).

sort函数大量使用容器中保存的任何类型的赋值运算符,但我似乎无法找出我定义的那个错误(程序在我定义之前正常运行).根据Accelerated C++(或至少这是我解释它的方式),赋值运算符应该工作的正确方法是首先销毁左操作数,然后使用等于右操作数的值再次构造它.所以这是我的重载operator =定义:

Student_info& Student_info::operator=(const Student_info& s)
{
    if(this != &s)
    {
        this->~Student_info();
        destroyCount++;

        *this = s;
    }

    return *this;
}
Run Code Online (Sandbox Code Playgroud)

如您所见,它调用Student_info复制构造函数,该构造函数定义如下:

Student_info::Student_info(const Student_info& s)
{
    name = s.name;
    midterm = s.midterm;
    final = s.final;
    finalGrade = s.finalGrade;
    homework = s.homework;

    copyCount++;
}
Run Code Online (Sandbox Code Playgroud)

复制构造函数正常运行,因为省略sort语句允许程序正常运行并产生大于0的copyCount(仅在复制构造函数和operator =中修改).

那么我的赋值运算符究竟出了什么问题呢?它与调用Student_info对象的破坏有关,但我不知道如何纠正它而不是破坏它.

(顺便说一下,复制构造函数,析构函数和赋值运算符的创建是通过Accelerated C++中的练习调用的......我意识到这些函数的合成版本显然足以满足我的类)

Pup*_*ppy 6

不不不.根本不应该那样工作.你当前的赋值运算符会破坏它所调用的对象,然后在被破坏的对象上调用自己(哦,嘿,无限递归)(哦,嘿,未定义的行为).你不应该破坏现有的对象.完全没有.并且这段代码*this = s根本不会调用任何构造函数,它会调用赋值运算符 - 这就是您刚才定义的.复制构造函数调用看起来像new (this) Student_info(s);.这是一种已知的模式,在许多方面都很糟糕.如果您有一本推荐它的书,请将其扔进垃圾箱.

赋值运算符应该将数据从右侧复制到左侧.在大多数情况下,最简单的方法就是复制每个数据成员.此运算符的语义不涉及破坏任何内容.任何使用此运算符的人都有权期望不会破坏正在进行的任何Student_info对象.

只需调用成员的现有赋值运算符,然后实现所需的任何其他逻辑.