Страницы

Поиск по вопросам

вторник, 28 января 2020 г.

Как правильно освободить память занятую элементами vector

#cpp #vector


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

void Company::makeOrder(const char* name, const float price)
{
    Order* new_order = new Order(name, price);
    orders_.push_back(new_order);
}


И в конце программы я хочу чтобы деструктор класса, который хранит в себе vector
удалил все его элементы, и если честно не получается, может кто подскажет?

class Order;

class Company
{
  public:
  Company(std::string name);
  virtual ~Company()
  {
    auto new_it = orders_.end();
    for(auto it = orders_.begin(); it != new_it; it++)
    {
        delete  OrderVector[*it];
    }
  }

  void makeOrder(const char* name, const float price);
  void removeOrdersByProductName(const char* name);


  void hire(const Employee& employee);
  void fire(const char* name);
  void renameEmployee(const char* old_name, const char* new_name);

  friend std::ostream& operator<<(std::ostream& out, const Company& company);

private:
  std::string name_;

  typedef std::list EmployeeList;
  EmployeeList employees_;

  typedef std::vector OrderVector;
  OrderVector orders_;
};

std::ostream& operator<<(std::ostream& out, const Company& company);

    


Ответы

Ответ 1



Данное предложение delete OrderVector[*it]; не имеет смысла. OrderVector - это имя типа. Поэтому применять к нему оператор индексирования бессмысленно. Все можно сделать без всякого написания вручную цикла с помощью стандартного алгоритма std::for_each и стандартного функционального объекта std::default_delete. Вот демонстрационная программа. #include #include #include #include struct Order { ~Order() { std::cout << "Order::~Order()" << std::endl; } }; typedef std::vector OrderVector; int main() { OrderVector orders = { new Order(), new Order(), new Order() }; std::for_each( orders.begin(), orders.end(), std::default_delete() ); return 0; } Ее вывод на консоль Order::~Order() Order::~Order() Order::~Order() Если хотите использовать цикл вместо алгоритма, то достаточно написать for ( auto order : orders ) delete order; Например, #include #include struct Order { ~Order() { std::cout << "Order::~Order()" << std::endl; } }; typedef std::vector OrderVector; int main() { OrderVector orders = { new Order(), new Order(), new Order() }; for ( auto order : orders ) delete order; return 0; } Результат будет такой же, что и для программы, показанной выше. Что касается вашего собственного цикла, то правильно его будет записать следующим образом: for ( auto it = orders_.begin(); it != orders_.end(); ++it ) { delete *it; } Обратите внимание, что вместо данного объявления конструктора Company(std::string name); будет лучше записать Company( const std::string &name ); Также в виду того, что вы используете вектор указателей, вам следует либо запретить копирование объектов класса, как, например, в определении класса записать Company( const Company & ) = delete; Company & operator =( const Company & ) = delete; Либо определить их явно.

Ответ 2



Если вы хотите чтобы при удалении элементов автоматически выполнялся их деструктор, то вам нужно либо завернуть указатели в "умные указатели", либо хранить в векторе не указатели, а сами объекты. Для первого варианта можно (и нужно!) использовать std::shared_ptr. Однако в этом случае деструктор Order будет вызываться не обязательно когда удаляется вектор. Он будет вызываться когда удалится последний умный указатель на его объект: #include #include typedef std::shared_ptr OrderPtr ; typedef std::vector OrderVector; OrderVector orders_; void Company::makeOrder(const char* name, const float price) { // безопасно создаем умный указатель auto new_order = std::make_shared(name, price); orders_.push_back(new_order); } Второй вариант, деструктор вектора автоматически вызовет деструкторы для каждого элемента: #include typedef std::vector OrderVector; OrderVector orders_; void Company::makeOrder(const char* name, const float price) { auto new_order = Order(name, price); orders_.push_back(new_order); } // а лучше так void Company::emplaceOrder(const char* name, const float price) { orders_.emplace_back(name, price); }

Ответ 3



Что такое delete OrderVector[*it];??? Вам нужно просто в цикле сделать delete *it; Однако имейте в виду, что если с вектором такой номер еще пройдет, то вот с другим типом контейнера запросто могут возникнуть проблемы. Контейнеры с более сложной структурой (set, unordered_map и т.п.) могут требовать того, чтобы все элементы контейнера содержали корректные значения во все моменты времени. Разрушать содержимое элемента контейнера в них можно только вместе с удалением (и только после удаления) самого элемента из контейнера. В том числе именно по этой причине имеет смысл использовать "умные указатели" для хранения указателей в контейнерах.

Ответ 4



Может, просто delete *it? :) Вам же надо удалять, передавая указатель, который хранится в элементе... Ваше OrderVector[*it] - это указатель, который хранится в векторе в элементе с номером, который представляет собой хранящийся в текущем элементе указатель, рассмотренный как целочисленное значение, т.е. с вероятностью 99.9999% фиг знает что, а не реальный указатель... P.S. Меня поправили - да, я не обратил внимания, что OrderVector - тип, а не вектор; мои пояснения относились к OrderVector, если бы это был вектор...

Комментариев нет:

Отправить комментарий