什么时候会用到拷贝构造函数?

1-什么时候会用到拷贝构造函数? 
2-什么时候有必要手动写拷贝构造函数?

1-什么时候会用到拷贝构造函数?
        当任何你想复印东西的时候,而不管东西被复印成什么样子。即任何你想利用一个已有的类实例给另一个类实例赋值时,这种赋值可能是显式的,也可能是隐式的
显式:classa_1=class_2;
隐式:函数的形参有用到类对象却没有用引用或传址技术时
            函数的返回值是一个对象也没有应用传址技术时
2-什么时候有必要用拷贝构造函数?
上述3种情况,如果没有涉及到深拷贝问题,就没有必要自己来编写拷贝构造函数,编译器有默认的可以很完美的完成任务
还一种情况就是变态的拷贝:在拷内过程中进行缩放,放大等处理,不过没什么用

//关于深拷贝 以下是引用:traceback:http://www.netology.cn/blog/user1/bachelor/archives/2006/375.html

关于深拷贝
如果一个类中含有指针成员变量,则在利用一个已存在对象构造新的对象时,就会面临两种选择:深拷贝和浅拷贝。
    浅拷贝只是将对象间对应的指针成员变量进行简单的拷贝,即拷贝结束后新旧对象的指针指向相同的资源(指针的值是相同的);这种拷贝会导致对象的成员不可用,如下例:
     class Person
     {
        public :
        //....
        char * home;//the person's home 
        void SetHome(char * str)
        {home = str;}
        ~Person()
         {
           //...
           delete [] home;
         }
     }
    //....
    char * place = new char [20];
    strcpy(place,"China");
    Person *A = new Person();
    A->SetHome(place);
    
    Person * B= Person(A);
    delete A;
   //....
   此时对象A 和对象B的成员home值相同,如果A对象 destroy,则对象B的成员home指向的地址变为不可用(对象A撤销时将home指向的资源释放了)。
    深拷贝是相对于浅拷贝而言的,为了避免上述情况的发生,将上例中的代码改造:对象拷贝时将指针指向的内容拷贝,代码如下:
   class Person
     {
        public :
        //....
        char * home;//the person's home 
        void SetHome(char * str)
        {home = str;}
        
        Person & Person(const Person & per)
        {
             //...
             if(* this == per)//copy itself
     return *this;
             home = new char[strlen(per.home) +1];//alloc new memory
    strcpy(home,per.home);
    return * this;
        } 
        ~Person()
         {
           //...
           delete [] home;
         }
     }
  深拷贝之后,新旧对象的home成员指向的内容的值相同,而其自身的值不同。这样就可避免出现其中之一
  destroy 之后,另一对象的home成员不可用。
  但是,此种开辟新的内存区域然后赋值拷贝的方法在面临指针成员指向的数据量很大时出现效率低下的问题,因此又有下面的处理方法:为指针保留引用计数(reference counting)。
  当类每次拷贝这个指针时,就增加它的计数;对象destroy时检察指针的引用计数,如果为0就删除其指向的资源,否则计数减小。如果指针所指数据相对恒定是,指针引用计数尤为有效。而且在数据量庞大的时候,可以有较高的执行效率。
   类示例代码如下:
 
//一个引用计数器很容易作为一个类来完成
//用于带一个引用计数值得void指针的类
class VoidRefPtr
{
 public:
  //constructor allocates memory for data
  VoidRefPtr(void * pData,int nSize)
  {
   ptr = malloc(nSize);
   memcpy(ptr,pData,nSize);
   nCount = 1;
  }

  //increment the reference count 
  VoidRefPtr * Ref()
  {
   nCount ++;
   return this;
  }
  
  //decrement the count and delete if zero 
  void Derf()
  {
   if(!--nCount)
    delete this;
  }
 
  ~VoidRefPtr()
  {
   delete ptr
  }
  
  void * ptr() 
  {
   return ptr
  }
 private:
  void * ptr;//the data
  unsigned int nCount;//the reference count
 
};
 
//这个类包含了一个实际的指针和用于对引用计数器自加自减的成员函数
//当引用计数器减到零时,对象撤销自身。
class RefcountCharPtr
{
public:
 RefcountCharPtr(const char * pData ="")
 {
  //constructor creates a ref pointer
  pRef = new VoidRefPtr((void *)pData,strlen(pData)+1);
 }
 
 RefcountCharPtr(const RefcountCharPtr &a)
 {
  //copy constructor increments ref count
  pRef = a.pRef->Ref();
 }
 
 ~RefcountCharPtr()
 {
  //destructor decrements ref count 
  pRef ->Derf();
 }
 
 const RefcountCharPtr & operator = (const RefcountCharPtr & a)
 {
  //asignment
  //decrement ref count of existing pointer
  pRef->Derf();
  //increment that of assigned pointer
  pRef = a.pRef->Ref();
  return * this;
 }
 
 RefcountCharPtr & operator =(const char * pData)
 {
  //char string assignment 
  //decrement ref count of existing pointer
  pRef->Derf();
  //make new pointer
  pRef = new VoidRefPtr((void *)pData,strlen(pData)+1);
  return *this;
 }
 
 //type conversion to a char string 
 operator const char * ()
 {
  return (char * )pRef->ptr();
 }

protected:
private:
 VoidRefPtr * pRef;
};
  一个同学给出了一个类似的实现:
   class RefData
{
 public:
  RefData(char *s)
  {
   data = new String(s);
  }
 int refCount;
 String *data;
};
 
class MyString
{
 public:
  MyString(const char *s = "");
 //...
 //...
 private:
  RefData * value; // 私有指针变量
};
 
MyString::MyString(const char *s = ""):value(new RefData(s))
{
}
 
MyString & MyString::operator=(const MyString & str)
{
 if (value == str.value) //如果是自己复制给自己
  return *this;
 if (--(value->refCount) == 0)
  delete value;
 value = s.value; // 只拷贝指针
 ++(value->refCount);
 return *this;
}
 
char & MyString::operator[](int dex) //改变值的时候
{
 if (value->refCount >1)
 {
  --value->refCount;
  value = new RefData(value->data)
 }
 return value->data[index];
}
 
//测试示例
int main()
{
 MyString s1 ="hello";
 char *p = &s1[1];
 MyString s2 = s1;
 *p = 'x';
}
 
  虽然引用计数的处理方法貌似不错,但是其亦存在其弊端:在多线程的条件下,其执行效率尤为低下。具体参见(Herb Shutter的在C++ Report杂志中的Guru专栏以及整理后出版的《More Exceptional C++》中专门的讨论)。
     
  最近在看设计模式的一些东东,偶然又发现了下面的一段:
  下面是一些可以使用Proxy模式的常见情况:
  ...
  4)智能指引(smart reference)--取代了简单的指针,它在访问对象时执行一些附加操作。它的典型用途包括:
   对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它(也称为 smartpointers[Ede92]).
   当第一次引用一个持久对象时,将它装入内存。
   在访问一个实际对象前,检察是否已经锁定了它,以确保其他对象不能改变它。
   以上的叙述的用途好像有些像引用计数,但是具体如何,现在偶还不是很清楚,准备将两者放在一起,看其联系和区别究竟如何。
   以上只是最近在看c++时遇到的一点问题,将其放在一起讨论,希望可以明白其原理和实现。
参考文章:
http://www.vckbase.com/document/viewdoc/?id=846
http://www.w3china.org/blog/more.asp?name=oceanblue&id=6786
http://gengwentao.blogchina.com/
参考书籍:
最优c/c++编程秘诀(The Best c/c++ Tips Ever) Anthony Porter 著 秦冬雷等译
设计模式 GOF

已标记关键词 清除标记
【为什么还需要学习C++?】 你是否接触很多语言,但从来没有了解过编程语言的本质? 你是否想成为一名资深开发人员,想开发别人做不了的高性能程序? 你是否经常想要窥探大型企业级开发工程的思路,但苦于没有基础只能望洋兴叹?   那么C++就是你个人能力提升,职业之路进阶的不二之选。 【课程特色】 1.课程共19大章节,239课时内容,涵盖数据结构、函数、类、指针、标准库全部知识体系。 2.带你从知识与思想的层面从0构建C++知识框架,分析大型项目实践思路,为你打下坚实的基础。 3.李宁老师结合4大国外顶级C++著作的精华为大家推出的《征服C++11》课程。 【学完后我将达到什么水平?】 1.对C++的各个知识能够熟练配置、开发、部署; 2.吊打一切关于C++的笔试面试题; 3.面向物联网的“嵌入式”和面向大型化的“分布式”开发,掌握职业钥匙,把握行业先机。 【面向人群】 1.希望一站式快速入门的C++初学者; 2.希望快速学习 C++、掌握编程要义、修炼内功的开发者; 3.有志于挑战更高级的开发项目,成为资深开发的工程师。 【课程设计】 本课程包含3大模块 基础篇 本篇主要讲解c++的基础概念,包含数据类型、运算符等基本语法,数组、指针、字符串等基本词法,循环、函数、类等基本句法等。 进阶篇 本篇主要讲解编程中常用的一些技能,包含类的高级技术、类的继承、编译链接和命名空间等。 提升篇: 本篇可以帮助学员更加高效的进行c++开发,其中包含类型转换、文件操作、异常处理、代码重用等内容。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页