c++浅拷贝和深拷贝

摘自《C++ Primer Plus》第6版 12.1.2和12.1.3ios

c++浅拷贝和深拷贝

浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,并且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不一样地址的指针。c++

c++ primer plus里深浅拷贝的图示:数据结构

逐个复制成员函数

深度复制this

 

示例:spa

#include <iostream>

using namespace std;

class StringBad
{
private:
    char * str;
    int len;
    static int num_strings;
public:
    StringBad(const char * s);
    StringBad();
    ~StringBad();
    friend ostream & operator<<(ostream & os, const StringBad &st);
};

int StringBad::num_strings = 0;

StringBad::StringBad(const char * s)
{
    len=strlen(s);
    str=new char(len+1);
    strcpy(str,s);
    num_strings++;
    cout << num_strings << ": /"" << str << "/" object created/n";
}

StringBad::StringBad()
{
    len=4;
    str=new char[4];
    strcpy(str,"C++");
    num_strings++;
    cout << num_strings << "; /"" << str << "/" object created/n";
}

StringBad::~StringBad()
{
    cout << "/"" << str << "/" object deleted, ";
    --num_strings;
    cout << num_strings << " left/n";
    delete [] str;
}

ostream & operator << (ostream &os, const StringBad &st)
{
    os << st.str;
    return os;
}

void callme1(StringBad &);
void callme2(StringBad);

int main()
{
    StringBad headline1("headline1");
    StringBad headline2("headline2");
    StringBad sports("sports");
    cout << "headline1: " << headline1 << endl;
    cout << "headline2: " << headline2 << endl;
    cout << "sports: " << sports << endl;
    callme1(headline1);
    cout << "headline1: " << headline1 << endl;
    callme2(headline2);
    cout << "headline2: " << headline2 << endl;
    cout << "Initialize one object to another: /n";
    StringBad sailor = sports;
    cout << "sailor: " << sailor;
    cout << "Assign one object to another: /n";
    StringBad knot;
    knot=headline1;
    cout << "knot: " << knot << endl;
    cout << "End of main" << endl;
    return 0;   
}

void callme1(StringBad & rsb)
{
    cout << "String passed by reference: /n";
    cout << "   /" " << rsb << " /"" << endl;
}

void callme2(StringBad sb)
{
    cout << "String passed by value: /n";
    cout << "   /" " << sb << " /"" << endl;
}

 

C++自动提供的成员函数: (若是没有定义)

  • 默认构造函数
  • 拷贝构造函数
  • 赋值构造函数
  • 默认析构函数
  • 地址操做符

1)默认构造函数

若是定义了构造函数,C++将不会生成默认构造函数。不然,编译器将提供这样的默认构造函数:指针

StringBad::StringBad(){}

 

2)拷贝构造函数

拷贝构造函数的原型是code

StringBad::StringBad(const StringBad &)

 什么时候调用拷贝构造函数:对象

   **  新建一个对象并将其初使化为同类对象,如
StringBad aa(headline1);
StringBad bb=headline1;
StringBad cc=StringBad(headline1);
StringBad * pdd=new StringBad(headline1);
其中,StringBad bb=headline1;
StringBad cc=StringBad(headline1);
可能会使用拷贝构造函数直接建立对象bb和cc,也有可能使用拷贝构造函数先生成一个临时对象,而后将临时对象的内容赋给bb和cc,这取决于具体的实现。
StringBad * pdd=new StringBad(headline1);会初使化一个匿名对象,并将新对象的地址赋给pdd指针内存

赋值操做符:

ANSI C 容许结构体赋值,C++容许对象赋值,经过自动重载赋值操做符实现的。

StringBad & StringBad::operator =(const StringBad &)

将已有的对象赋给另外一个对象时,将使用重载的赋值操做符。

StringBad kk("just a test");

StringBad aa;

aa=kk;

但初使化对象的时候,使用的是拷贝构造函数

StringBad & StringBad::operator=(const StringBad &st)

{

    if(this==&st)

        return *this;

    delete [] str;

    len=st.len;

    str=new char[len+1];

    strcpy(str,st.str);

    retern *this;

}

 

修改后代码

#include <iostream>

using namespace std;

class StringGood
{
private:
        char * str;
        int len;
        static int num_strings;
public:
        StringGood(const char * s);
        StringGood(const StringGood & st);
        StringGood();
        ~StringGood();
        friend ostream & operator<<(ostream & os, const StringGood &st);
        StringGood & operator = (const StringGood &);
};

int StringGood::num_strings = 0;

StringGood::StringGood(const char * s)
{
        len=strlen(s);
        str=new char(len+1);
        strcpy(str,s);
        num_strings++;
        cout << num_strings << ": /"" << str << "/" object created/n";
}

StringGood::StringGood(const StringGood & st)
{
        len=st.len;
        str=new char[len+1];
        strcpy(str,st.str);
        num_strings++;
        cout << num_strings << ": /"" << str << "/" object created/n";
}

StringGood::StringGood()
{
        len=4;
        str=new char[4];
        strcpy(str,"C++");
        num_strings++;
        cout << num_strings << "; /"" << str << "/" object created/n";
}

StringGood::~StringGood()
{
        cout << "/"" << str << "/" object deleted, ";
        --num_strings;
        cout << num_strings << " left/n";
        delete [] str;
}

ostream & operator << (ostream &os, const StringGood &st)
{
        os << st.str;
        return os;
}

StringGood & StringGood::operator = (const StringGood &st)
{
        if(this==&st)
                return *this;
        delete[] str;
        len=st.len;
        str=new char[len+1];
        strcpy(str,st.str);
        return *this;
}

void callme1(StringGood &);
void callme2(StringGood);

int main()
{
        StringGood headline1("headline1");
        StringGood headline2("headline2");
        StringGood sports("sports");
        cout << "headline1: " << headline1 << endl;
        cout << "headline2: " << headline2 << endl;
        cout << "sports: " << sports << endl;
        callme1(headline1);
        cout << "headline1: " << headline1 << endl;
        callme2(headline2);
        cout << "headline2: " << headline2 << endl;
        cout << "Initialize one object to another: /n";
        StringGood sailor = sports;
        cout << "sailor: " << sailor << endl;
        cout << "Assign one object to another: /n";
        StringGood knot;
        knot=headline1;
        cout << "knot: " << knot << endl;
        cout << "End of main" << endl;
        return 0;
}

void callme1(StringGood & rsb)
{
        cout << "String passed by reference: /n";
        cout << "   /" " << rsb << " /"" << endl; 
}

void callme2(StringGood sb)
{
        cout << "String passed by value: /n";
        cout << "   /" " << sb << " /"" << endl;
}

 

使用场景

1. 只要类里有指针时,就要写本身版本的拷贝构造函数和赋值操做符函数。这两个函数中能够拷贝那些被指向的数据结构,从而使每一个对象都有本身的拷贝;或者能够采用某种引用计数机制,去跟踪当前有多少个对象指向某个数据结构。(也能够静态计数对象的个数,好比c++ primer plus第六版的例子,static int num_strings)

2. 某些类在实现拷贝构造函数和赋值操做符时,能够确信程序中不会作拷贝和赋值操做的时候,去实现它们会得不偿失,所以能够:只声明这些函数(声明为private成员)而不去定义实现它们。这就防止了会有人去调用它们,也防止了编译器去生成它们。

3. 浅拷贝在构造和析构对象时容易产生问题,如无必要尽可能不用浅拷贝。当咱们要传递复杂结构的信息,而又不想产生另外一份数据时,可使用浅拷贝,好比引用传参。

4. 智能指针是浅拷贝概念的加强。好比智能指针能够维护一个引用计数来代表指向某块内存的指针数量,只有当引用计数减至0时,才真正释放内存。

相关文章
相关标签/搜索