Освобождение памяти с помощью delete против умного указателя и правильный способ освобождения памяти - PullRequest
4 голосов
/ 06 мая 2019

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

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

class Company
{
private:
    std::string companyInfo;
    std::vector<Employee * > employees;
    std::vector<Team *> teams;
public:
    Company();
    ~Company();

    std::string getCompanyInfo() const;
    void setCompanyInfo(const std::string & companyInfo);
    bool addEmployee(Employee * employee, const std::string & teamName);
    bool addTeam(Team * team);
    void printTeams() const;
    void printEmployees() const;
};

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

Company::~Company()
{
    for (Employee * e : employees) {
        delete e;
    }

    employees.clear();

    for (Team * t : teams) {
        delete t;
    }

    teams.clear();
}

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

Заранее спасибо и извините, если мои вопросы выглядят глупо.

Ответы [ 3 ]

3 голосов
/ 06 мая 2019

Вы должны никогда писать delete в логике кода, если вы не знаете, что делаете. Это правило. Всякий раз, когда вы нарушаете это правило, ожидайте возникновения всевозможных проблем. Другими словами: всегда используйте стандартные контейнеры + умные указатели.

Уникальный указатель: Простая оболочка вокруг вашего указателя, которая удалит ресурс под ним, когда он выйдет из области видимости. Вы не можете копировать уникальные указатели, потому что тогда кто будет владеть указателем, если вы можете? Кто его удалит? Только 1 объект должен иметь возможность удалить его.

Общий указатель: Делает возможным копирование, но за счет наличия (атомарного) счетчика, который подсчитывает, сколько объектов ссылаются на один указатель. Когда счетчик обнуляется, ресурс под указателем удаляется.

2 голосов
/ 06 мая 2019

Это правильный способ освобождения памяти

Если предположить, что контейнеры заполнены оператором new, как это,

employees.push_back(new Employee());
teams.push_back(new Team());

, тогда даэто правильный способ очистки этих ресурсов.

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

Обычно да.Вы можете настроить, как умный указатель выполняет свою работу по удалению ресурса, которым он управляет, но поведение по умолчанию является правильным для вашего случая (вызов delete).

, если я использую уникальный или общийуказатель

Первый выбор должен быть std::unique_ptr.Он более эффективен, чем std::shared_ptr, и более ограничен в том, как может использоваться объект, которым он управляет.Но это связано с ограничениями, например, класс с std::unique_ptr членами данных (например, Company в вашем случае) не может быть скопирован.Использование std::shared_ptr вместо этого смягчает эту проблему, но имеет совершенно другую семантику - копирование объекта Company означает совместное использование команд и сотрудников.Это может быть не то, что вы хотите.Одним из способов решения этой проблемы является использование std::unique_ptr, реализация конструкторов копирования и копирования для Company в терминах так называемых виртуальных конструкторов Employee::clone() и Team::clone() функций-членов.

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

Пример:

void someFunction()
{
    Company c;

    // stuff...

} // the scope ends here, ~Company will be called
1 голос
/ 06 мая 2019

Является ли это правильным способом освобождения памяти

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

Очистка векторов, тем не менее, избыточна.Векторы практически уничтожены, поэтому их элементы все равно будут очищены.

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

Вы можетеисправить эту проблему, а также упростить деструктор (вы можете просто использовать неявный деструктор) с помощью интеллектуальных указателей.

если я буду использовать уникальный или общий указатель

Да, вам следует.

Ваш код демонстрирует уникальное право собственности - Company уникально владеет Employee s и Team s, поэтому самое простое изменение - использование уникальных указателей.

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

Это деструктор умного указателя, который удаляет указатель.

Когда умный указатель является локальной переменной,это уничтожено в конце области.Так же, как если Company является локальной переменной, она уничтожается в конце области видимости, и ее деструктор запускается.

Когда умный указатель является членом, он уничтожается, когда суперобъектуничтожены.В вашем случае у вас был бы вектор умных указателей, и в этом случае умный указатель уничтожается, когда вектор уничтожается, или умный указатель стирается из вектора.

...