C++类的复制构造函数

复制构造函数的形式为:

class ClassName
{
...

ClassName(ClassName&)
{
...
}
或
ClassName(const ClassName&)
{
...
}
...
};

如果没有定义复制构造函数,则编译器会为该类自动生成复制构造函数。如果用户自定义了任何一个类型的复制构造函数,则不再生成默认的复制构造函数。

生成的默认构造函数只是简单地进行值的复制。对于包含指向动态分配的内存空间的指针变量来说,复制构造函数只是将指针变量的值复制给新的变量,而使得两个对象中的变量指向同一个内存空间。这就会造成数据之间的耦合,甚至会出现多次删除同一个指针的问题,会产生严重的错误。因此,对于包含这类成员变量的类来说,其复制构造函数需要自定义,需要为新的对象中的变量分配新的内存空间,并根据源对象的变量的值填充该内存空间。与以值复制相比,这种类型的复制成为“深拷贝”,而以值的复制的形式称为“浅拷贝”。

/*****************************************
 * copy_constructor.cpp                  *
 *                                       *
 * C++类的复制构造函数(浅拷贝带来的多次释放内存 *
 * 错误                                   *
 ****************************************/


class Test
{
private:
  int i;
  int *p;

public:
  Test()
  {
    i = 10;
    p = new int(5);
  }

  //浅拷贝
  Test(const Test& t)
  {
    i = t.i;
    p = t.p;
  }

  ~Test()
  {
    delete p;
  }

};

int main()
{
  Test t;
  Test t1(t);

  return 0;
}

多次释放错误

/****************************************
 * copy_constructor_2.cpp               *
 *                                      *
 * C++类的复制构造函数(深拷贝)          *
 ****************************************/

#include <iostream>
using namespace std;

class Test
{
private:
  int i;
  int *p;

public:
  Test()
  {
    i = 10;
    p = new int(5);
  }

  //深拷贝
  Test(const Test& t)
  {
    i = t.i;
    p = new int(*t.p);
  }

  ~Test()
  {
    delete p;
  }

public:
  void Print()
  {
    cout<<"i = "<<i<<","<<"*p = "<<*p<<endl;
  }
};

int main()
{
  Test t;
  t.Print();
  Test t1(t);
  t1.Print();
  return 0;
}

深拷贝
复制构造函数应用于以下三种情况:

  • 使用一个对象去初始化同类的另一个对象
  • 在类的对象作为函数参数的情况下,当函数调用时,其复制构造函数被调用
  • 当类的对象作为函数的返回值时,当函数返回时,该类的复制构造函数被调用。
/****************************************
 * copy_constructor_3.cpp               *
 *                                      *
 * 复制构造函数应用的三种情况           *
 ****************************************/

#include <iostream>
using namespace std;

class A
{
private:
  static int id;
public:
  int value;
public:
  A(int value)
  {
    id++;
    this->value = value;
  }

  A(const A& a)
  {
    value = a.value;
    id++;
    cout<<"复制构造函数(id)"<<id<<"被调用"<<endl;
  }

};

int A::id = 0;

void UsingAAsPara(A a)
{
}

A UsingAAsReturn()
{
  A a(15);
  return a;
}

int main()
{
  A a(10);

  cout<<"A b(a): ";
  A b(a);
  cout<<"A c = a:";
  A c = a;
  cout<<"UsingAAsPara(c)";
  UsingAAsPara(c);
  cout<<"UsingAAsReturn()";
  cout<<UsingAAsReturn().value<<endl;
  return 0;
}

使用情况
使用g++编译器发现第三种情况下并没有调用复制构造函数,而是使用的带参数value的构造函数。可见,g++编译器对这种情况进行了优化,见下面的标准中的描述。

12.8 When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.118) This elision of copy operations is permitted in the following circumstances (which may be combined
to eliminate multiple copies):
— in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type, the copy operation can be omitted by constructing the automatic object directly into the function’s return value
— when a temporary class object that has not been bound to a reference (12.2) would be copied to a class object with the same cv-unqualified type, the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy
[ Example:
class Thing {
    public :
        Thing ();
        ~ Thing ();
        Thing ( const Thing &);
};
Thing f () {
    Thing t;
    return t;
}
Thing t2 = f();
Here the criteria for elision can be combined to eliminate two calls to the copy constructor of class Thing: the copying of the local automatic object t into the temporary object for the return value of function f() and the copying of that temporary object into object t2. Effectively, the construction of the local object t can be viewed as directly initializing the global object t2, and that object’s destruction will occur at program exit. —end example ]

参考文献

https://www.coursera.org/course/pkupop

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值