1

Тема: Не зрозуміло чому вилітає програма

Задача: Ведення особових справ робітників у відділі кадрів.

Маю ось такі основні класи:

Прихований текст
class Worker;

class Department
{
    string name;
    vector<Worker*> workers;
    string major_department_name;
    double amount_prize;
    string *positions;
    int number_positions;
public:
    Department() : workers(0)
    {
        name = "no name department";
        major_department_name = "no name";
        amount_prize = 0;
        positions = NULL;
        number_positions = 0;
    }

    Department(const Department &obj)
    {
        name = obj.name;
        major_department_name = obj.major_department_name;
        amount_prize = obj.amount_prize;

        if (!workers.empty())
            workers.clear();
        for (int i = 0; i < obj.workers.size(); ++i)
            workers.push_back(obj.workers[i]);

        number_positions = obj.number_positions;

        positions = obj.positions;
        
    }

    void SetName(string name)
    {
        if (ValidInputNameSurname(name))
            this->name = name;
    }

    string GetName()
    {
        return name;
    }

    void SetMajorDepartmentName(string major_name)
    {
        if (ValidInputNameSurname(name))
            major_department_name = major_name;
    }

    string GetMajorDepartmentName()
    {
        return major_department_name;
    }

    void AddWorker(Worker *worker)
    {
        workers.push_back(worker);
    }

    void DeleteWorkerFromDepartment(Worker *worker)
    {
        if (workers.empty())
            throw new Empty; //cout << "In department no workers\n";

        vector<Worker*>::iterator find_pos = find(workers.begin(), workers.end(), worker);

        if (find_pos != workers.end())
            workers.erase(find_pos);
    }

    int GetNumberWorkers()
    {
        return workers.size();
    }

    int GetNumberPositions()
    {
        return number_positions;
    }

    vector<Worker*>& GetListWorkers()
    {
        return workers;
    }

    void SetAmountPrize(double amount_prize)
    {
        if (ValidInputNumber(amount_prize))
            this->amount_prize = amount_prize;
    }

    double GetAmountPrize()
    {
        return amount_prize;
    }

    void AddPositions(string position_name)
    {
        if (positions == NULL)
        {
            number_positions = 1;

            positions = new string[number_positions];

            positions[number_positions - 1] = position_name;
        }
        else
        {
            string* temp_positions = new string[number_positions + 1];

            int k = 0;
            while (k < number_positions && positions[k] != position_name)
                ++k;
            if (k == number_positions)
            {
                for (int i = 0; i < number_positions; ++i)
                    temp_positions[i] = positions[i];
                temp_positions[number_positions] = position_name;

                delete[]positions;
                positions = temp_positions;
                ++number_positions;
            }
        }
    }

    void DeletePositions(string position_name)
    {
        if (positions == NULL)
            cout << "\nIn the department no any positions\n";
        else
        {
            int i = 0;
            while (i < number_positions && positions[i] != position_name)
                ++i;
            if (i < number_positions)
            {
                string* temp_positions = new string[number_positions - 1];

                for (int j = 0; j < i; ++j)
                    temp_positions[j] = positions[j];
                for (int j = i; j < number_positions - 1; ++j)
                    temp_positions[j] = positions[j + 1];

                delete[]positions;
                positions = temp_positions;
                --number_positions;
            }
        }
    }

    string GetPosition(int index)
    {
        --index;
        if (index < 0 || index >= number_positions)
            throw new WrongIndex;
        return positions[index];
    }

    void Show()
    {
        cout << "\nName: " << name << "\n";
        cout << "\nMajor department name: " << major_department_name << "\n";
        cout << "\nAmount prize: " << amount_prize << "\n";
        cout << "\nPositions:\n";
        for (int i = 0; i < number_positions; ++i)
            cout << "\n" << i + 1 << ")" << positions[i] << "\n";
    }

    void Input()
    {
        cin.ignore(255, '\n');
        string temp;

        cout << "\nDepartment name: ";
        getline(cin, temp);
        if (!ValidInputNameSurname(temp))
            throw new WrongInputNameSurname;
        name = temp;

        cout << "\nMajor department name: ";
        getline(cin, temp);
        if (!ValidInputNameSurname(temp))
            throw new WrongInputNameSurname;
        major_department_name = temp;

        cout << "\nAmount prize: ";
        cin >> temp;
        if (!IsValidDigit(temp))
            throw new IsNoValidDigits;
        double number = atof(temp.c_str());
        amount_prize = number;
    }

    ~Department()
    {

        if (positions != NULL)
        {
            delete[]positions;
            positions = NULL;
            number_positions = 0;
        }
    }
};

const int NUMBER_LAST_PROJECTS = 5;

class Worker : public Person
{
    static int account_number_salary;
    Department department;
    Position position;
    Project projects[NUMBER_LAST_PROJECTS];
    int current_number_projects;
    double experience;
    double total_projects_cost;
public:
    Worker() : position(), projects(), department()
    {
        Project temp_project;
        for (int i = 0; i < NUMBER_LAST_PROJECTS; ++i)
            projects[i] = temp_project;

        current_number_projects = 0;
        experience = 0;
        total_projects_cost = 0;
    }

    void Show()
    {
        cout << account_number_salary << setw(10) << name << setw(11) << surname << setw(9) << birthday << setw(15) << phone_number << setw(10);
        cout << department.GetName() << setw(10) << position.GetName() << setw(8) << experience << setw(8) << position.GetSalary() << "\n";
    }

    void ShowProjects()
    {
        if (current_number_projects != 0)
        {
            for (int i = 0; i < current_number_projects; ++i)
                projects[i].Show();
            cout << "\n";
        }
        else
            cout << "No projects\n";
    }

    static int GetAccountNumberSalary()
    {
        return account_number_salary;
    }

    void SetDepartment(Department department)
    {
        this->department = department;
    }

    Department GetDepartment()
    {
        return department;
    }

    void SetDepartmentName(string name)
    {
        department.SetName(name);
    }

    string GetDepartmentName()
    {
        return department.GetName();
    }

    void SetPosition(Position position)
    {
        this->position = position;
    }

    Position GetPosition()
    {
        return position;
    }

    void SetPositionName(string pos_name)
    {
        position.SetName(pos_name);
    }

    string GetPositionName()
    {
        return position.GetName();
    }

    double GetSalary()
    {
        return position.GetSalary();
    }

    void SetNewProject(Project project)
    {
        if (current_number_projects < NUMBER_LAST_PROJECTS)
        {
            projects[current_number_projects] = project;
            ++current_number_projects;
        }
        else if (current_number_projects == NUMBER_LAST_PROJECTS)
        {
            for (int i = 0; i < current_number_projects - 1; ++i)
                projects[i] = projects[i + 1];
            projects[current_number_projects - 1] = project;
        }
    }

    Project* GetProjects()
    {
        return projects;
    }

    void SetExperience(double experience)
    {
        if (!ValidInputNumber(experience))
            throw new IsNegativeNumber;
        this->experience = experience;
    }

    double GetExperience()
    {
        return experience;
    }

    double CountTotalProjectsCost()
    {
        for (int i = 0; i < current_number_projects; ++i)
            total_projects_cost += projects[i].GetProjectCost();

        return total_projects_cost;
    }

    void InputWorker()
    {
        cin.ignore(255, '\n');

        string temp;

        ++account_number_salary;
        cout << "Account number salary(ANS) assigned automaticaly: " << account_number_salary << "\n";

        cout << "Enter surname: ";
        getline(cin, temp);

        if (!ValidInputNameSurname(temp))
            throw new WrongInputNameSurname;
        surname = temp;

        cout << "Enter name: ";
        getline(cin, temp);

        if (!ValidInputNameSurname(temp))
            throw new WrongInputNameSurname;
        name = temp;

        cout << "Enter birthday (dd.mm.yyyy): ";
        getline(cin, temp);
        birthday = temp;

        cout << "Enter phone number: ";
        getline(cin, temp);
        if (!ValidInputPhoneNumber(temp))
            throw new WrongInputPhoneNumber;
        phone_number = temp;

        cout << "Enter education: ";
        getline(cin, temp);
        if (!ValidInputString(temp))
            throw new Empty;
        education = temp;

        Project temp_project;
        temp_project.Input();
        SetNewProject(temp_project);

        cout << "What experience: ";
        cin >> temp;
        if (!IsValidDigit(temp))
            throw new IsNoValidDigits;

        double temp_experience = atof(temp.c_str());
        experience = temp_experience;
    }

};

І ось основні функції, які задіяні, коли виникає помилка:

Прихований текст
Worker *CreateNewBaseWorker(int &number_workers, Department *&departments, int &number_departments)
{
    cout << "Enter the number of workers: ";
    cin >> number_workers;

    if (number_workers == 0)
        number_workers = 1;

    string dep_name, position_name;
    Worker *temp = new Worker[number_workers];
    for (int i = 0; i < number_workers; ++i)
    {
        temp[i].InputWorker();
        cout << "Department name: ";
        cin >> dep_name;
        cout << "Position name: ";
        cin >> position_name;
        temp[i].SetDepartmentName(dep_name);
        temp[i].SetPositionName(position_name);
        AddWorkerInDepartment(departments, number_departments, temp[i]);
    }

    return temp;
}

void AddWorkerInDepartment(Department *&departments, int &number_departments, Worker worker)
{
    if (departments == NULL)
    {
        AddDepartment(departments, number_departments);
        worker.SetDepartment(departments[number_departments - 1]);
        departments[number_departments - 1].AddWorker(&worker);
    }
    else
    {
        int i = 0;
        while (i < number_departments && departments[i].GetName() != worker.GetDepartmentName())
            ++i;
        if (i < number_departments)
        {
            departments[i].AddWorker(&worker);
            worker.SetDepartment(departments[i]);
        }
        else
        {
            AddDepartment(departments, number_departments);
            worker.SetDepartment(departments[i]);
            departments[i].AddWorker(&worker);
        }

    }
}

І, власне, сама проблема: при створенні масиву працівників заповнення масиву відбуваєть нормально, але програма видає помилку при виході із функції AddWorkerInDepartment, тобто вже коли все встановлено.
Ось саме повідомлення:

Прихований текст

http://i.imgur.com/ebMnrm0.png

В чому може бути проблема?

2

Re: Не зрозуміло чому вилітає програма

А як викликається CreateNewBaseWorker?

3

Re: Не зрозуміло чому вилітає програма

Ось з цієї функції:

Прихований текст
void AddWorker(Worker *&workers, int &number_workers, Department *&departments, int &number_departments)
{
    if (departments == NULL)
        departments = CreateDepartments(number_departments);
    
    if (workers == NULL)
        workers = CreateNewBaseWorker(number_workers, departments, number_departments);
    else
    {
        Worker *new_workers = new Worker[number_workers + 1];
        for (int i = 0; i < number_workers; ++i)
            new_workers[i] = workers[i];
        delete[]workers;
        workers = new_workers;
        workers[number_workers].InputWorker();
        AddWorkerInDepartment(departments, number_departments, workers[number_workers]);
        ++number_workers;
    }
    
}

4

Re: Не зрозуміло чому вилітає програма

А чому дорівнюють departments і number_departments?

5

Re: Не зрозуміло чому вилітає програма

Дивіться - ви всюди передаєте workers і number_workers, departments і number_departments разом. Це означає, що вони мають бути об'єднані в якусь єдину сутність. Наприклад, vector, або ж якийсь об'єкт, що керує ними одночасно.

6

Re: Не зрозуміло чому вилітає програма

В AddWorkerInDepartment передається копія Worker, Worker не має конструктора копіювання. Може там десь баг вилазить?

Подякували: koala, pika19892

7

Re: Не зрозуміло чому вилітає програма

У вас ця жахлива структура, де в кожного працівника є свій власний департамент...

Ок, дивіться, що відбувається: ви передаєте в AddWorkerInDepartment(..., Worker worker) копію працівника (з копіями усіх його департаментів і посад, але то вже інша історія). Після чого пхаєте посилання на цю копію в departments[ i ].AddWorker(&worker), який зберігає посилання на цю копію в workers.push_back(worker). А далі AddWorkerInDepartment закінчується, worker випадає з області видимості і припиняє своє існування у яскравому спалаху деструктора. Але посилання на нього тепер зафіксоване в масиві workers, і коли до нього буде звертання - відбудеться... ну, власне, те, що відбувається у вас.

Подякували: pika1989, tachiorz2

8

Re: Не зрозуміло чому вилітає програма

koala написав:

У вас ця жахлива структура, де в кожного працівника є свій власний департамент...

Це не у мене, а у завданні... Такі вимоги... Я вже з ними голову зламала: четвертий день сиджу і ніяк до толку привести не можу.

koala написав:

Ок, дивіться, що відбувається: ви передаєте в AddWorkerInDepartment(..., Worker worker) копію працівника (з копіями усіх його департаментів і посад, але то вже інша історія). Після чого пхаєте посилання на цю копію в departments[ i ].AddWorker(&worker), який зберігає посилання на цю копію в workers.push_back(worker). А далі AddWorkerInDepartment закінчується, worker випадає з області видимості і припиняє своє існування у яскравому спалаху деструктора. Але посилання на нього тепер зафіксоване в масиві workers, і коли до нього буде звертання - відбудеться... ну, власне, те, що відбувається у вас.

Я думала про деструктор, але ніяк не могла зрозуміти чому...