vector中使用拷贝构造函数和解除const的关键字const_cast介绍

一、深拷贝和浅拷贝

浅拷贝,假如在定义一个类A,然后使用类似A obj;  A obj1(obj);或者A obj1 = obj; 时候,由于没有自定义拷贝构造函数,C++编译器自动会产生一个默认的拷贝构造函数。这个默认的拷贝构造函数采用的是“位拷贝”(浅拷贝),而非“值拷贝”(深拷贝)的方式,如果类中含有指针变量,默认的拷贝构造函数必定出错。

浅拷贝:只是对指针的拷贝,拷贝后两个指针指向同一个内存空间

深拷贝:不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

举一个例子,当我使用vetcorobj申明一个obj容器之后,obj.push_back(obj1)此时就会调用浅拷贝,但是这样会带来一个严重的问题:当obj1释放掉内部的指针时,obj[0]内部的指针也被释放掉了,这样就会产生野指针。


二、vector和拷贝构造函数

vector其中一个特点:内存空间只会增长,不会减小,援引C++ Primer:为了支持快速的随机访问,vector容器的元素以连续方式存放,每一个元素都紧挨着前一个元素存储。设想一下,当vector添加一个元素时,为了满足连续存放这个特性,都需要重新分配空间、拷贝元素、撤销旧空间,这样性能难以接受。因此STL实现者在对vector进行内存分配时,其实际分配的容量要比当前所需的空间多一些。就是说,vector容器预留了一些额外的存储区,用于存放新添加的元素,这样就不必为每个新元素重新分配整个容器的内存空间。

在调用push_back时,每次执行push_back操作,相当于底层的数组实现要重新分配大小;这种实现体现到vector实现就是每当push_back一个元素,都要重新分配一个大一个元素的存储,然后将原来的元素拷贝到新的存储,之后在拷贝push_back的元素,最后要析构原有的vector并释放原有的内存。例如下面程序:

#include 
#include 
#include 

using namespace std;

class Point
{
public:
        Point()
        {
            cout << "construction" << endl;
        }
        Point(const Point& p)//拷贝构造函数
        {
            cout << "copy construction" << endl;
        }
        ~Point()
        {
            cout << "destruction" << endl;
        }
};

int main()
{
    vector pointVec;
    Point a;
    Point b;
    pointVec.push_back(a);
    pointVec.push_back(b);

    cout<

输出结果:


其中执行

pointVec.push_back(a);

此时vector会申请一个内存空间,并调用拷贝构造函数将a放到vector中

再调用

pointVec.push_back(b);

此时内存不够 需要扩大内存,重新分配内存 这时再调用拷贝构造函数将a拷贝到新的内存,再将b拷入新的内存,同时有人调用Point拷贝构造函数,最后释放原来的内存 此时调用Point的析构函数。

注:当释放vector的时候,用clear只能清空vector的内容,而不释放内存,所以需要使用erase。

三、消除const修饰对象时带来错误

当我们使用拷贝构造函数的时候,参数内必须用const修饰,此时如果调用该对象的方法时,就会报出这样的错误:

对象引用前加const报错:不能将“this”指针从“const a”转换为“a &”

解决方法看别人的博客发现有三种方法:

1. 解决方法一:不使用const
2. 使用const_cast(ptr),进行相应的转化
 A * b = const_cast(obj); //obj代表实际应该使用的对象,此时用一个新对象b来消除const限定
 b->GetIt();//编译就没错了
 
   
3.将相关的函数转化成相应的const函数
class A
{
     int m_It;
public:
     int GetIt() const;
}
int A::GetIt() const//这个地方也要加const
{
   return m_It;
}
附上项目中遇到这个问题,解决之后的主要代码
Action::Action(const Action &action)        //拷贝构造函数,进行深拷贝
{
    EffeciencyState* pEffeciencyState = NULL;
    Action* pAction = const_cast(&action);  //解决const限定
    for(int i = 0; i < pAction->getEffeciencyStateList().length(); i++)
    {
        if(pAction->getEffeciencyStateList()[i]->getType() == normal)
        {
            pEffeciencyState = new EffeciencyState();
            pEffeciencyState->setEffeciencyStateName(pAction->getEffeciencyStateList()[i]->getEffeciencyStateName());
            pEffeciencyState->setEffeciencyStateTime(pAction->getEffeciencyStateList()[i]->getEffeciencyStateTime());
            pEffeciencyState->setDescription(pAction->getEffeciencyStateList()[i]->getDescription());
        }
        else
        {
            pEffeciencyState = new HttpRequest();
            pEffeciencyState->setEffeciencyStateName(pAction->getEffeciencyStateList()[i]->getEffeciencyStateName());
            pEffeciencyState->setEffeciencyStateTime(pAction->getEffeciencyStateList()[i]->getEffeciencyStateTime());
            pEffeciencyState->setDescription(pAction->getEffeciencyStateList()[i]->getDescription());
            pEffeciencyState->setDuringTime(pAction->getEffeciencyStateList()[i]->getDuringTime());
        }
        m_oEffeciencyStateList.push_back(pEffeciencyState);
    }
    m_sActionName = pAction->getActionName();
    m_bVisitState = pAction->getVisitState();
    m_oBeginTime = pAction->getBeginTime();
    m_oEndTime = pAction->getEndTime();
    m_oStateNumberMap = pAction->getStateNumberMap();
    m_oStepActionList = pAction->getStepActionList();
}

c++新手,如果有不对的地方希望能帮忙指正,多谢。




你可能感兴趣的:(c++)