当struct对象超出范围时,如何删除struct对象内的指针?

时间:2015-11-09 21:16:09

标签: c++ pointers struct memory-leaks

我有一个包含指向对象的指针的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;}));

3 个答案:

答案 0 :(得分:4)

您可以使用智能指针:

struct Track
{
    std::unique_ptr<KalmanFilter> kalmanFilter;
....
};

这意味着当Track被销毁时,如果智能指针正在管理指针,它将在该指针上调用delete

可以通过以下方式分配:

track.kalmanFilter.reset(new KalmanFilter(contours[contour].centroid));

尽管Track的构造函数完成此操作会更好。

此更改将使Track不可复制(但仍可移动)。这是一件好事,因为以前你的代码在被复制时表现不正常,所以现在编译器会为你捕获它。

您需要修改擦除循环以停止复制元素。执行此操作的常规方法是使用vector::erasestd::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对象的副本。副本和原始对象都指向相同的内存,并且在某些时候都被破坏,导致同一地址的双重释放。遵循关于更好的代码组织的评论中的建议将有助于避免此类错误。