程序的优化续,类是否要有拷贝构造函数,深浅拷贝问题

一:来看一个程序优化的例子

#include <iostream>
using namespace std;
class X
{
public:
    X()
    {
        cout << "调用了默认构造函数" << endl;
    }

    X(const X&)
    {
        cout<<"调用了拷贝构造函数"<<endl;
    }

    ~X()
    {
        cout << "调用了析构函数" << endl;
    }

    X(int a) : m_i(a)
    {
        cout << "调用了X(int a)函数" << endl;
    }

public:
    int m_i;
};

int main(void)
{
    cout << "-------begin-------" << endl;

    X x0(100);

    X x1 = 100;

    X x2 = X(100);

    X x3 = (X)100;

    cout << "-------end-------" << endl;

    return 0;
}

来看执行结果:
在这里插入图片描述
这是加了防止优化编译后的结果,,再来看看优化后的执行结果。

在这里插入图片描述
对比两次的执行结果可以知道,如果要用一个对象给另一个对象赋值,使用第一种代码的赋值效果是最好的,,因为它没有调用多余的构造函数,,,,后面3种赋值代码,,编译器,,首先是构造出了一个临时对象,然后临时对象通过拷贝构造函数把值赋给了自己定义的对象,,所以才多了调用拷贝构造函数这一步骤。

结论:如果要用一个对象给另一个对象赋值,使用第一种代码的赋值效果是最好的。

二:一个类是否必须有拷贝构造函数?

答:非必须,,如果一个类里只有一些普通的数据类型,例如int double等等,则不必有拷贝构造函数,因为编译器有默认的bitwise(按位拷贝)这种拷贝机制,,例如:

#include <iostream>
using namespace std;
class X
{
public:
    X()
    {
        cout << "调用了默认构造函数" << endl;
    }
    ~X()
    {
        cout << "调用了析构函数" << endl;
    }

    X(int a) : m_i(a)
    {
        cout << "调用了X(int a)函数" << endl;
    }

public:
    int m_i;
};

int main(void)
{   
    X x0;
    x0.m_i=100;

    X x1(x0);//如果有拷贝构造函数就会调用拷贝构造函数
    
    cout<<x1.m_i<<endl;

    return 0;
}

来看执行结果:
在这里插入图片描述
在没有拷贝构造函数的情况下,由于有bitwise的存在,所以x1的成员m_i它的值就会变成100了(按位拷贝)。

再来看看一下情况:

#include <iostream>
using namespace std;
class X
{
public:
    X()
    {
        cout << "调用了默认构造函数" << endl;
    }
    ~X()
    {
        cout << "调用了析构函数" << endl;
    }
    X(const X& p)
    {
        cout<<"调用了拷贝构造函数"<<endl;
    }
    X(int a) : m_i(a)
    {
        cout << "调用了X(int a)函数" << endl;
    }

public:
    int m_i;
};

int main(void)
{   
    X x0;
    x0.m_i=100;

    X x1(x0);//如果有拷贝构造函数就会调用拷贝构造函数

    cout<<x1.m_i<<endl;

    return 0;
}

在这里插入图片描述
程序多了一个拷贝构造函数,由于拷贝构造函数里没有任何的拷贝动作,所以输出的值是不对的,,这个时候由于有了拷贝构造函数就不会执行bitwise了。

所以要想输出的值是对的就要我们自己加上赋值的动作。
即:

 m_i=p.m_i;

(3)深浅拷贝问题
来看以下例子:

#include <iostream>
using namespace std;
class X
{
public:
    X()
    {
        p=new int(100);
        cout << "调用了默认构造函数" << endl;
    }
    virtual  ~X()
    {
        delete p;
        cout << "调用了析构函数" << endl;
    }
    /* X(const X& p1)
    {
        p=new int(100);
        cout<<"调用了拷贝构造函数"<<endl;
    } */
    X(int a) : m_i(a)
    {
        p=new int(100);
        cout << "调用了X(int a)函数" << endl;
    }

public:
    int m_i;
    int *p;
};

int main(void)
{   
    X x0;
    x0.m_i=100;

    X x1(x0);//如果有拷贝构造函数就会调用拷贝构造函数

    cout<<x1.m_i<<endl;
    
    return 0;
}

这个例子中,类里多了一个指针,由于没有拷贝构造函数,所以在执行X x1(x0)这一步时是按bitwise方式拷贝,这个时候问题就来了,由于bitwise是按值来拷贝的,也就是说,x1的p指向的那段内存单元和x0的p指向的那段内存单元是一样的,这个可以单步调试看,,,所以等到对x0和x1析构的时候,,,那就会造成对这个内存单元delete两次了,,所以这个程序会报错,,,这就是浅拷贝,,,,所以这种情况下就需要自己定义拷贝构造函数了。

改造后的代码如下:

#include <iostream>
#include<stdlib.h>
#include<cstring>
using namespace std;
class X
{
public:
    X()
    {
        p=new int(1000);
        cout << "调用了默认构造函数" << endl;
    }
    virtual  ~X()
    {
        delete p;
        cout << "调用了析构函数" << endl;
    }
     X(const X& p1)
    {
        m_i=p1.m_i;
        p=new int(1000);
        memcpy(p,p1.p,sizeof(int));//自己指向拷贝的动作,深拷贝(把目标对象的内容拷贝过来)

        cout<<"调用了拷贝构造函数"<<endl;
    } 
    X(int a) : m_i(a)
    {
        p=new int(1000);
        cout << "调用了X(int a)函数" << endl;
    }

public:
    int m_i;
    int *p;
};

int main(void)
{   
    X x0;
    x0.m_i=100;

    X x1(x0);//如果有拷贝构造函数就会调用拷贝构造函数

    cout<<x1.m_i<<endl;
	 cout<<*(x1.p)<<endl;
    return 0;
}

这个时候由于x0的p和x1的p不是指向同一个内存段了,,所以析构的时候就不会出现delete同一段内存两次的情况了,所以程序可以正常的执行。

程序执行结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_38158479/article/details/106883988