Удалить элемент из vector и очистить память
при очистки памяти через итератор возникает исключение.
#include <stdint.h>
#include <vector>
#include "Shared.h"
using namespace std;
const int RangeItems = 3;
struct Anchor
{
uint16_t anchor_addr;
float range[RangeItems];
float dbm;
Anchor(uint16_t addr) : anchor_addr(addr), dbm(0) {}
};
struct Link
{
vector<Anchor> Anchors;
Link()
{
Anchors.reserve(10); //зарезервировать сразу N элементов
}
};
struct Link* init_link(uint16_t addr)
{
Link* l = new Link();
Anchor* a = new Anchor(addr);
l->Anchors.push_back(*a);
return l;
}
void add_To_End(struct Link* p, uint16_t addr)
{
Anchor* a = new Anchor(addr);
p->Anchors.push_back(*a);
}
Result delete_Anchor(Link* p, uint16_t addr)
{
for (auto it = p->Anchors.begin(); it != p->Anchors.end(); ++it)
{
Anchor a = *it;
if (a.anchor_addr == addr)
{
p->Anchors.erase(it);
delete &a; //ECXEPTION!!!!!
return Succsess;
}
}
return NotFound;
}
Тестирую работу с вектором
int main()
{
uwb_data= init_link(1);
add_To_End(uwb_data, 2);
add_To_End(uwb_data, 3);
add_To_End(uwb_data, 4);
auto res = delete_Anchor(uwb_data, 3);
}
При удалении элемента из вектора, хочу очистить занимаемую элементом Anchor память, но возникает Исключение.
Ответы (2 шт):
А получается вот что:
- Вызов uwb_data=
init_link(1);создаетLinkиAnchorв свободной памяти с адресами соответственноXL1иXA1, потом заносит копиюAnchorв вектор объектаLink, который выделяет памятьYA1для этого объекта.
То, что мы сохранили адрес
XL1вuwb_data, вселяет надежду, что мы потом можем освобождать эту память(хотя вы этого не пытаетесь делать).
Дальше _ вызов
add_To_End(uwb_data, 2);создаетAnchorс адресомXA2и заносит копиюAnchorв вектор (объекта подuwb_data), который выделяет памятьYA2для этого объекта.(в векторе уже два таких объекта)Вызов:
delete_Anchor(uwb_data, 1)находит вuwb_data->Anchorsдва схожих объекта и удаляет их. Таким образом вектор освобождает памятьYA1иYA2
delete &a;становится ошибкой, потому чтоaесть локальный объект. Но если вы пытаетесь каким то образом удалить объект вектора, то это тоже ошибка, потому что вектор уже его удалил.
Аупала,Впропала. Что осталось на трубе? А осталисьXA1,XA2иXL1. И, если, последний хранится вuwb_data, и после использования можно написатьdelete uwb_data, то информация о первых двух потеряна.
Есть много вариантов решения:
- не создавать
Anchorв свободной памяти, а просто переместить в векторAnchors.emplace_back(Anchor(1))(наверное так лучше) - или после
push_back(*a)освобождать память пода(ведь объект все равно уже не нужен, так как в векторе его копия) - Использовать умные указатели
- или(плохой вариант) где то хранить указатели на объекты, созданных в динамической области нами(не распределителем вектора). Но нужно ли это?...
Вектор, как и все стандартные контейнеры, хранит копии того, что вы в него добавляете.
Т.е. вот здесь:
Anchor* a = new Anchor(addr);
p->Anchors.push_back(*a);
в вектор попадает копия объекта, т.е. delete на ней вызывать не надо, это надо делать на оригинале, на a. Вы этого не делаете, поэтому здесь утечка памяти.
В этом же причина краша - вы зовете delete не на том объекте, который создали в куче, а на его копии, которую создал вектор.
Вообще, в современном C++ почти никогда не нужно использовать new и delete, если только вы не делаете свой аналог вектора или чего-то подобного.
Правильно добавлять элемент так: .emplace_back(addr); или .push_back(Anchor(addr)); (для вашего класса .push_back(addr); тоже сработает). При удалении delete не нужен, достаточно erase.
Link тоже нет смысла создавать через new. Просто Link l; ... return l;. И еще, раз вы пишете на С++ а не на С, то вместо struct Link достаточно писать просто Link (везде кроме самого определения структуры).