拷贝构造、赋值构造、深拷贝、浅拷贝、位拷贝、值拷贝

很早之前,一直对这些名词很不解,翻看了c++ primer很多次,也只知道其用法,不知其解。说白了,就是不知道为什么有这些各式的拷贝的存在,或者是说在何种环境下面要使用得上!今天无意翻到当初写的小例子,重新整理后帖上来作个记号!

 

//=================================

一,在什么环境下面可能需要使用自定义拷贝、赋值构造?

 

 在解释这些名词之前,需要知道一点,在什么环境下面需要使用自定义拷贝、赋值构造,答案就是:当一个自定义的structclass中包括有指针对象时(可能是堆栈资源或是文件等等,以前总以为只是普通指针),拷贝构造和赋值构造就可能需要自定义(是否重定义取决于类的实现模型是否需要,以前总以为是必须要实现),因为你需要明确的定义当class发生拷贝或赋值构造时,class中的那些指针对象所指向的资源也是否需要COPY一个副本(重新分配堆栈)。当没有自定义构造函数时,系统的默认拷贝和赋值构造函数只对指针进行位拷贝,即只对二个class中的指针进行”=”赋值,指针所指向的的堆栈资源仍然是一样的,这时就会发生二种情况:其中一个类中指针对象被析构时,虽一个类的指针便会成野指针,调用时程序异常或崩溃;二,当二个类都析构时,二个指针对象所指向的堆栈会被delete二次,造成内存泄露。可是,可是也不是所有的指针对象在发生拷贝构造时都需要重新分配堆栈,请参第五条!

 

//=================================

二,名词解释:

 

拷贝构造、赋值构造:

拷贝构造:复制构造函数是一种特殊构造函数,具有单个形参,该形参(常用 const 修饰)是对该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数。当将该类型的对象传递给函数或函数返回该类型的对象时,将隐式使用复制构造函数。(c++ primer原话

赋值构造:与复制构造的行为一样,只是通过重载“=”,通过=来将目标初始化自己。虽然行为一样,但实现时有区别,需要排除是否是 “自己=自己”, 是否有“先前的指针对象没有delete”的情况!

浅拷贝(位拷贝)、深拷贝(值拷贝):

浅拷贝:当发生拷贝或赋值构造时,系统将依次调用目标类的每一个成员变量的操作符“=”来初始化自己类的成员变量; 但二个class中都有指针对象时,二个指针进行”=”操作时,指针的值将是一样的(指向的堆栈是一样的)。

反之深拷贝:行为跟浅拷贝一样,只是针对指针对象时,被构造的类会先将为自己的针对对象分配新的堆栈,然后再将目标类中的指针所指向的堆栈进行memcpy。 

 

三,=================================

demo

class CFoo
{
public:
    CFoo()
        :m_pStr( NULL )
    {

    }

    CFoo( const CFoo& rhs )
    {
        m_pStr = new std::string;
        *m_pStr = *rhs.m_pStr;
    }

    void init( const std::string &str )
    {
        if ( !m_pStr )
        {
            m_pStr  = new std::string;
            *m_pStr = str;
        }
    }

    CFoo& operator=( const CFoo& rhs )
    {
        if ( this == &rhs )  // 判断是否是自己给自己赋值
            return *this;

        if ( m_pStr )        // 判断是不是已经申请过堆栈的指针,没有这一步,会导致已申请过的堆栈没有进行delete导致的内存泄露
        {
            delete m_pStr;
            m_pStr = NULL;
        }

        m_pStr = new std::string;
        *m_pStr = *rhs.m_pStr;

        return *this;
    }

    ~CFoo()
    {
        if ( m_pStr )
        {
            delete m_pStr;
            m_pStr = NULL;
        }
    }

    void printSth()
    {
        if ( m_pStr )
        {
            std::cout << " this: " << this << " , m_pStr addrs: " << m_pStr << " , m_pStr value: " << *m_pStr << std::endl;
        }
        else
        {
            std::cout << " this: " << this << " , m_pStr is NULL " << std::endl;
        }
    }

private:
    std::string *m_pStr;
};

int _tmain(int argc, _TCHAR* argv[])
{
/
    // [ 拷贝构造和赋值 ]
    CFoo foo;
    foo.init( "test!!!");
    foo.printSth();

    CFoo foo2( foo );  // 拷贝构造
    foo2.printSth();

    CFoo foo3 = foo;  // 这里并不是赋值,而是拷贝构造
    foo3.printSth();

    CFoo foo4;
    foo4.printSth();
    foo4 = foo;       // 这里才是赋值构造
    foo4.printSth();
//
    
    return 0;
}


//=================================

四,何时会发生拷贝构造?

以下情况都会调用拷贝构造函数:
1)一个对象以值传递的方式传入函数体 
2)一个对象以值传递的方式从函数返回 
3)一个对象需要通过另外一个对象进行初始化

 

 

//=================================

五,在什么环境下面可能需要使用浅拷贝、深拷贝?


无论深浅,都是需要的。当深拷贝发生时,通常表明存在着一个聚合或组合的关系“,而浅拷贝发生时,通常表明存在着一个弱的“关联关系 

二种情况:

1,指针成员对象是class的成员变量,指针的堆栈和生命周期都是由class自己来维护和管理,那么,当拷贝发生时,需要自定义拷贝、赋值构造函数,对指针指向的资源进行深拷贝。

2,指针成员对象是class的成员变量,但堆栈的申请和生命周期由其它类来维护和管理,那么,这个类发生拷贝时,只能进行浅拷贝。 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值