我有一个包含指向对象的指针的struct对象。
struct Track
{
KalmanFilter* kalmanFilter; //Kalman filter for this track
....
};
我通过
实例化struct和pointer对象Track track;
track.kalmanFilter = new KalmanFilter(contours[contour].centroid);
....
然后我通过
检查每个帧是否仍然有效//Temporary vector to hold alive tracks
std::vector<Track> tempTracks;
for(...)
{
//If track is valid save into temp tracks
if(tracks[track].deadTime <= deadTime) tempTracks.push_back(tracks[track]);
}
//Save all temp tracks back into tracks - this removes dead tracks that were in tracks
tracks = tempTracks;
过了一段时间我使用的微控制器耗尽了内存,这是我代码中唯一的指针,所以我非常确定KalmanFilter指针没有被删除。
到目前为止,我已经在Track结构中尝试了一个析构函数,这会导致我的微控制器立即出现硬故障。
//Destructor frees up Kalman filter memory when the Track object goes out of scope
~Track()
{
if(kalmanFilter) delete kalmanFilter;
}
我尝试使用unique_ptr但是我无法获得编译代码,我发现的所有示例都实例化了实例化unique_ptr时指向的对象。就我而言,我不认为我能做到这一点。
处理这种情况的正确方法是什么?
由于
修改
因此,根据评论,似乎有两个要点。
在构造函数中分配内存
我已将我的结构重写为
struct Track
{
Track(const Point& initialPosition) : kalmanFilter(initialPosition) {}
~Track() {}
KalmanFilter kalmanFilter; //Kalman filter for this track
};
我通过
实例化它Track track(contours[contour].centroid);
这是对的吗?
找到更好的删除曲目的方法
从循环中删除索引时,从向量中删除对象的最佳方法是什么?使用STL迭代器?
我实施了@ M.M的解决方案似乎有效
tracks.erase(std::remove_if(tracks.begin(), tracks.end(), [&](Track const &t){return t.deadTime > deadTime;}));
答案 0 :(得分:4)
您可以使用智能指针:
struct Track
{
std::unique_ptr<KalmanFilter> kalmanFilter;
....
};
这意味着当Track
被销毁时,如果智能指针正在管理指针,它将在该指针上调用delete
。
可以通过以下方式分配:
track.kalmanFilter.reset(new KalmanFilter(contours[contour].centroid));
尽管Track
的构造函数完成此操作会更好。
此更改将使Track
不可复制(但仍可移动)。这是一件好事,因为以前你的代码在被复制时表现不正常,所以现在编译器会为你捕获它。
您需要修改擦除循环以停止复制元素。执行此操作的常规方法是使用vector::erase
与std::remove_if
结合使用(后者将所选元素移至末尾,erase
将元素删除到最后):
tracks.erase( std::remove_if( begin(tracks), end(tracks),
[&](Track const &t) { return t.deadTime > deadTime; } ), end(tracks) );
必填包括<memory>
和<algorithm>
。
答案 1 :(得分:1)
您消除死音轨的方式将导致每首曲目的许多副本。
对于其中一个副本的析构函数将尝试释放该内存,而主动副本仍在使用可能导致问题的kalman过滤器。此外,如果您在分配之前无法保证它是NULL,则可能是一个被删除的随机指针。
在这种情况下,我会使用共享指针。但说实话,我觉得你的存储/使用轨道有一个更好的整体结构,我必须考虑它,并了解更多有关实现的内容。
答案 2 :(得分:-1)
当你执行push_back()时,您将创建原始Track对象的副本。副本和原始对象都指向相同的内存,并且在某些时候都被破坏,导致同一地址的双重释放。遵循关于更好的代码组织的评论中的建议将有助于避免此类错误。