首页 > 代码库 > 类的再理解
类的再理解
参考资料:
http://zhidao.baidu.com/link?url=Fjt8F2-hATIAzY3lvj8aMUNuKoHhkaH8K0ixvJCHMQdwmob5NRDaYAVGBBXo4nONHgLeBiLUBpIq-T0i8axsmK8Pjz6Ozz7Nennr-b3HBGi c++自定义类型中有个vector容器,容器里面是一些指针,如何写这个类的复制构造函数和重载=符?
最近遇到一个很奇怪的问题:
莫名其妙的有内存泄漏:而且下图中的109.2Mb 会一直增加,且是运行一段时间后再增加。
可能原因:
1、Object* 没有清理造成的。
2、vector 较多造成的内存泄漏。
方案1:
用类对象,然后自己写清理函数:
加入.clear()一直报错。
后来认为是vector弄得鬼,内存没有释放掉。然后用 .clear() 和 .swap()配合使用。
但是还是会有问题。
一、人为的管理 Object*
1先把之前的Object干掉,然后将现在的obs放到last_obs当中去。
2、将ESR剩下的点,放到Obs当中去。
然后,干掉ESR当中加入的Point2D
不过,这种方式不可行,失败了。
二、利用类来管理
之前,用last_obs = obs; 来进行赋值,直接报错。因为类设计的有问题。之前一直没有注意类里面的复制构造函数以及 = 重载符。
这些在类里面有vector《T》 ,当T是指针的时候特别有用。因为,这里面会涉及到类的赋值和=。
比如: OBJ *p1 = other.m.at(i); OBJ*p2 = new OBJ(*p1); ,这里面的OBJ(*p1)就是一个复制构造函数,这个和初始化的构造函数不太一样。
我们在使用类的时候,最容易犯的错误就是
int*p = new int(); int*p1 = new int() ; p1 = p; delete p;
这个时候两个指针是指向的同一块地址,刚开始P1开辟了一块空的地址,但是在p1 = p的时候,此空的地址被P的地址替代。当p被释放的同时,P1也被释放。所以,这种错误一定要避免。
这个时候,复制构造函数和=重载符,就派上用场了。
详细的过程参见类:
Object类对象:
- #ifndef OBJECT_H
- #define OBJECT_H
- typedef struct Point2dFloat
- {
- float x;
- float y;
- }Point2dFloat;
- static bool comp(const Point2dFloat &a, const Point2dFloat &b);
- class Object //激光雷达数据不用过滤 ,速度值在获取数据的时候得到,计算时间差
- {
- public:
- Point2dFloat m_objBoxCenter;
- Point2dFloat m_relVelocity;
- std::vector<Point2dFloat> m_contourPoints;
- Point2dFloat getObjBoxCenter() //一线激光雷达中心点,可以设置为 y 坐标的最近点。
- {
- m_objBoxCenter.x = 0;
- m_objBoxCenter.y = 0;
- if (m_contourPoints.size() > 1)
- {
- //sort(m_contourPoints.begin(),m_contourPoints.end(),comp);
- //m_objBoxCenter.x = (m_contourPoints[0].x + m_contourPoints[m_contourPoints.size()-1].x)/2;
- //m_objBoxCenter.y = (m_contourPoints[0].y + m_contourPoints[m_contourPoints.size()-1].y)/2;
- //根据y去筛选
- int cc = 0;
- float y = 10000;
- for (int i = 0; i < m_contourPoints.size(); ++i)
- {
- if (m_contourPoints[i].y < y)
- {
- y = m_contourPoints[i].y;
- cc = i;
- }
- }
- m_objBoxCenter.x = m_contourPoints[cc].x;
- m_objBoxCenter.y = m_contourPoints[cc].y;
- }
- else
- {
- m_objBoxCenter.x = m_contourPoints[0].x/2;
- m_objBoxCenter.y = m_contourPoints[0].y/2;
- }
- return m_objBoxCenter;
- }
- float m_speed;
- //方法2
- Point2dFloat m_pre_objBoxCenter;
- Point2dFloat m_pre_relVelocity; //上一次的数据
- Point2dFloat m_next_objBoxCenter;
- Point2dFloat m_next_relVelocity; //预测的数据
- Object() //初始化构造函数
- {
- m_contourPoints.clear();
- }
- Object(const Object& org) //拷贝(复制)构造函数 vector在执行类指针和对象的时候,会调用到此函数
- {
- m_objBoxCenter = org.m_objBoxCenter;
- m_relVelocity = org.m_relVelocity;
- m_contourPoints = org.m_contourPoints;
- m_speed = org.m_speed;
- m_pre_objBoxCenter = org.m_pre_objBoxCenter;
- m_pre_relVelocity = org.m_pre_relVelocity;
- m_next_objBoxCenter = org.m_next_objBoxCenter;
- m_next_relVelocity = org.m_next_relVelocity;
- }
- ~Object()//析够函数
- {
- m_contourPoints.clear();
- vector<Point2dFloat>(m_contourPoints).swap(m_contourPoints);//这才是释放内存空间
- }
- };
- bool comp(const Point2dFloat &a, const Point2dFloat &b)
- {
- return a.x > b.x; //x 升序
- }
- #endif
管理Object的管理类对象:
ObjectList 类对象。
- #pragma once
- #include "VirtualSwitchZmq.h"
- #include "Object.h"
- class ObjectList
- {
- public:
- ObjectList() //构造函数 参数初始化
- {
- m_objects.clear();
- tick = 0;
- };
- ~ObjectList() //析构函数 释放掉其他资源 (关键的地方)
- {
- if (m_objects.size() > 0)
- {
- for (int i = 0; i < m_objects.size(); ++i)
- {
- delete m_objects.at(i);
- m_objects.at(i) = NULL;
- }
- m_objects.clear();
- }
- }
- ObjectList(const ObjectList& other) //复制构造函数
- {
- for (int i = 0; i < other.m_objects.size(); ++i) //将其他类对象深拷贝给当前的对象。
- {
- Object* p1 = other.m_objects.at(i);
- Object* p2 = new Object(*p1); //注意:类里面还有类的话,也需要支持复制构造函数
- m_objects.push_back(p2);
- }
- tick = other.tick; //深拷贝包括其他成员变量
- }
- ObjectList &operator=(const ObjectList& other) //重载=符
- {
- if (&other != this) //不同的对象
- {
- for (int i = 0; i < m_objects.size(); ++i) //先释放掉之前开辟的指针,并将指针置空。
- {
- delete m_objects.at(i);
- m_objects.at(i) = NULL;
- }
- m_objects.clear(); //空间置0.
- for (int i = 0; i < other.m_objects.size(); ++i) // 将其他类对象赋值给本身的类对象,注意返回的是类对象,而不是类指针。
- {
- Object*p1 = other.m_objects.at(i); //当我们用指针间进行=的时候,需要*p = *q; 这样写才是规范的。
- Object*p2 = new Object(*p1);
- m_objects.push_back(p2);
- }
- tick = other.tick;
- }
- return *this;
- }
- void addElem(Object* elem) //封装m_objects,利用函数进行元素的增加和减少
- {
- m_objects.push_back(elem);
- }
- int getSize()
- {
- return m_objects.size();
- }
- std::vector<Object*> m_objects;
- //同步到ms
- long tick;
- };
目前上面的封装还是有些问题,后面需要根据需要再修改。
调用:
刚开始清零,然后赋值给上一个last_obs,然后将obs释放掉。
三、换用智能指针
Shared_ptr<> (); make_share<>(); 成对使用。
管理动态创建的对象的销毁,原理是记录对象被引用的 次数。
Std::tr1 或者 boost:: 里面都有,假如同时加入两个命名空间。需要指明命名空间。
目前还没有掌握好如何正确使用智能指针,但是对于上面的问题,不知道用智能指针如何上手,后续增加相关功能。
类的再理解