C ++: Определен мой собственный оператор присваивания для моего типа, теперь .sort () не будет работать с векторами моего типа? - PullRequest
2 голосов
/ 26 января 2011

У меня есть класс (те, кто читал 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);

Функция calculator () использует объекты этого типа. Как часть функции, вектор (уже объявленных) объектов Student_info сортируется с использованием универсальной функции сортировки библиотеки. Моя программа не продвигается дальше этой точки (хотя, согласно NetBeans, никакие исключения не генерируются и программа корректно завершается).

Функция сортировки интенсивно использует оператор присваивания любого типа, который содержится в контейнере, но я не могу понять, что не так с тем, что я определил (программа работала правильно, прежде чем я ее определил). Согласно Accelerated C ++ (или, по крайней мере, так я его интерпретировал), правильный способ работы оператора присваивания состоит в том, чтобы сначала уничтожить левый операнд, а затем построить его снова со значением, равным правому операнду. Так что это мой перегруженный оператор = определение:

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

        *this = s;
    }

    return *this;
}

Как видите, он вызывает конструктор копирования 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++;
}

Конструктор копирования работает правильно, потому что отсутствие оператора сортировки позволяет программе функционировать правильно и выдает copyCount (который изменяется только в конструкторе копирования и операторе =) больше 0.

Так что именно не так с моим оператором присваивания? Это связано с уничтожением вызывающего объекта Student_info, но я не знаю, как его исправить, если не уничтожить его.

(И, между прочим, создание конструктора копирования, деструктора и оператора присваивания требует упражнение в Accelerated C ++ ... Я понимаю, что синтезированные версии этих функций, очевидно, подойдут для моего класса)

Ответы [ 3 ]

6 голосов
/ 26 января 2011

Нет, нет, нет. Это не должно работать так вообще. Ваш текущий оператор присваивания уничтожает вызываемый объект, а затем вызывает себя (о, эй, бесконечная рекурсия) на уничтоженном объекте (о, эй, неопределенное поведение). Вы не должны уничтожать существующий объект. Совсем. И этот код *this = s вообще не вызывает никакого конструктора, он вызывает оператор присваивания, который вы только что определили. Вызов конструктора копирования будет выглядеть как new (this) Student_info(s);. Это известная схема, и это ужасно во многих отношениях. Если у вас есть книга, которая рекомендует ее, выбросьте ее в корзину .

Оператор присваивания должен копировать данные с правой стороны на левую. Самый простой способ сделать это в большинстве случаев - просто скопировать каждый элемент данных. Семантика этого оператора не предполагает уничтожения чего-либо. Любой, кто использует этот оператор, имеет право ожидать, что не будет никакого уничтожения каких-либо объектов Student_info.

Просто вызовите существующие операторы присваивания члена и затем реализуйте любую дополнительную логику, которая вам нужна.

2 голосов
/ 26 января 2011
*this = s;

это бесконечная рекурсия.это не конструктор копирования, это оператор присваивания

1 голос
/ 26 января 2011
struct Student_info {
  Student_info& operator=(Student_info other) {
    swap(*this, other);
    return *this;
  }

  friend void swap(Student_info &a, Student_info &b) {
    using std::swap;
    #define S(N) swap(a.N, b.N);
    S(name)
    S(midterm)
    S(final)
    S(finalGrade)
    S(homework)
    #undef S
  }

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

Получатели, установщики и другие функции-члены для краткости опущены

Если у вас есть общедоступные методы получения и установки, которые являются просто образцом, рассмотрите возможность пометить соответствующие элементы данных как открытые.

...