首页 > 代码库 > 类的再理解

类的再理解

 

参考资料:

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类对象:

  1. #ifndef OBJECT_H
  2. #define OBJECT_H
  3.  
  4.  
  5. typedef struct Point2dFloat
  6. {
  7.    float x;
  8.    float y;
  9. }Point2dFloat;
  10.  
  11. static bool comp(const Point2dFloat &a, const Point2dFloat &b);
  12.  
  13. class Object //激光雷达数据不用过滤 ,速度值在获取数据的时候得到,计算时间差
  14. {
  15. public:
  16.     Point2dFloat m_objBoxCenter;
  17.  
  18.     Point2dFloat m_relVelocity;
  19.  
  20.     std::vector<Point2dFloat> m_contourPoints;
  21.  
  22.     Point2dFloat getObjBoxCenter() //一线激光雷达中心点,可以设置为 y 坐标的最近点。
  23.     {
  24.        m_objBoxCenter.x = 0;
  25.        m_objBoxCenter.y = 0;
  26.  
  27.        if (m_contourPoints.size() > 1)
  28.        {
  29.           //sort(m_contourPoints.begin(),m_contourPoints.end(),comp);
  30.           //m_objBoxCenter.x = (m_contourPoints[0].x + m_contourPoints[m_contourPoints.size()-1].x)/2;
  31.           //m_objBoxCenter.y = (m_contourPoints[0].y + m_contourPoints[m_contourPoints.size()-1].y)/2;
  32.  
  33.          //根据y去筛选
  34.  
  35.           int cc = 0;
  36.           float y = 10000;
  37.           for (int i = 0; i < m_contourPoints.size(); ++i)
  38.           {
  39.              if (m_contourPoints[i].y < y)
  40.              {
  41.                 y = m_contourPoints[i].y;
  42.                 cc = i;
  43.              }
  44.           }
  45.           m_objBoxCenter.x = m_contourPoints[cc].x;
  46.           m_objBoxCenter.y = m_contourPoints[cc].y;
  47.        }
  48.        else
  49.        {
  50.           m_objBoxCenter.x = m_contourPoints[0].x/2;
  51.           m_objBoxCenter.y = m_contourPoints[0].y/2;
  52.        }
  53.       return m_objBoxCenter;
  54.     }
  55.  
  56.    float m_speed;
  57.  
  58.    //方法2
  59.     Point2dFloat m_pre_objBoxCenter;
  60.     Point2dFloat m_pre_relVelocity; //上一次的数据
  61.  
  62.     Point2dFloat m_next_objBoxCenter;
  63.     Point2dFloat m_next_relVelocity; //预测的数据
  64.  
  65.  
  66.     Object() //初始化构造函数
  67.     {
  68.         m_contourPoints.clear();
  69.     }
  70.  
  71.     Object(const Object& org) //拷贝(复制)构造函数 vector在执行类指针和对象的时候,会调用到此函数
  72.     {
  73.        m_objBoxCenter = org.m_objBoxCenter;
  74.        m_relVelocity = org.m_relVelocity;
  75.        m_contourPoints = org.m_contourPoints;
  76.        m_speed = org.m_speed;
  77.        m_pre_objBoxCenter = org.m_pre_objBoxCenter;
  78.        m_pre_relVelocity = org.m_pre_relVelocity;
  79.        m_next_objBoxCenter = org.m_next_objBoxCenter;
  80.        m_next_relVelocity = org.m_next_relVelocity;
  81.     }
  82.  
  83.     ~Object()//析够函数
  84.     {
  85.        m_contourPoints.clear();
  86.        vector<Point2dFloat>(m_contourPoints).swap(m_contourPoints);//这才是释放内存空间
  87.     }
  88.  
  89. };
  90. bool comp(const Point2dFloat &a, const Point2dFloat &b)
  91. {
  92.    return a.x > b.x; //x 升序
  93. }
  94.  
  95.  
  96. #endif

管理Object的管理类对象:

ObjectList 类对象。

  1. #pragma once
  2.  
  3. #include "VirtualSwitchZmq.h"
  4. #include "Object.h"
  5.  
  6. class ObjectList
  7. {
  8.    public:
  9.       ObjectList() //构造函数 参数初始化
  10.       {
  11.          m_objects.clear();
  12.          tick = 0;
  13.       };
  14.  
  15.       ~ObjectList() //析构函数 释放掉其他资源 (关键的地方)
  16.       {
  17.          if (m_objects.size() > 0)
  18.          {
  19.             for (int i = 0; i < m_objects.size(); ++i)
  20.             {
  21.                delete m_objects.at(i);
  22.                m_objects.at(i) = NULL;
  23.             }
  24.             m_objects.clear();
  25.          }
  26.  
  27.       }
  28.  
  29.  
  30.       ObjectList(const ObjectList& other) //复制构造函数
  31.       {
  32.          for (int i = 0; i < other.m_objects.size(); ++i) //将其他类对象深拷贝给当前的对象。
  33.          {
  34.             Object* p1 = other.m_objects.at(i);
  35.             Object* p2 = new Object(*p1); //注意:类里面还有类的话,也需要支持复制构造函数
  36.             m_objects.push_back(p2);
  37.          }
  38.          tick = other.tick; //深拷贝包括其他成员变量
  39.       }
  40.  
  41.       ObjectList &operator=(const ObjectList& other) //重载=符
  42.       {
  43.          if (&other != this) //不同的对象
  44.          {
  45.             for (int i = 0; i < m_objects.size(); ++i) //先释放掉之前开辟的指针,并将指针置空。
  46.             {
  47.                delete m_objects.at(i);
  48.                m_objects.at(i) = NULL;
  49.             }
  50.             m_objects.clear(); //空间置0.
  51.  
  52.             for (int i = 0; i < other.m_objects.size(); ++i) // 将其他类对象赋值给本身的类对象,注意返回的是类对象,而不是类指针。
  53.             {
  54.                Object*p1 = other.m_objects.at(i); //当我们用指针间进行=的时候,需要*p = *q; 这样写才是规范的。
  55.                Object*p2 = new Object(*p1);
  56.                m_objects.push_back(p2);
  57.             }
  58.             tick = other.tick;
  59.          }
  60.          return *this;
  61.       }
  62.  
  63.       void addElem(Object* elem) //封装m_objects,利用函数进行元素的增加和减少
  64.       {
  65.          m_objects.push_back(elem);
  66.       }
  67.  
  68.       int getSize()
  69.       {
  70.          return m_objects.size();
  71.       }
  72.  
  73.       std::vector<Object*> m_objects;
  74.    //同步到ms
  75.       long tick;
  76. };

 

目前上面的封装还是有些问题,后面需要根据需要再修改。

 

调用:

刚开始清零,然后赋值给上一个last_obs,然后将obs释放掉。

技术分享

技术分享

技术分享

 

 

三、换用智能指针

Shared_ptr<> (); make_share<>(); 成对使用。

管理动态创建的对象的销毁,原理是记录对象被引用的 次数。

Std::tr1 或者 boost:: 里面都有,假如同时加入两个命名空间。需要指明命名空间。

目前还没有掌握好如何正确使用智能指针,但是对于上面的问题,不知道用智能指针如何上手,后续增加相关功能。

 

类的再理解