精华内容
下载资源
问答
  • C++默认拷贝构造函数

    千次阅读 2019-07-24 17:13:42
    C++默认拷贝构造函数 转载来源 c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于: (1)当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且其函数体为空; (2)...

    C++默认拷贝构造函数

    转载来源
    c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于:
    (1)当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且其函数体为空;
    (2)当类中没有定义拷贝构造函数时,编译器会默认提供一个拷贝构造函数,进行成员变量之间的拷贝。(这个拷贝操作是浅拷贝)
    这里只讲拷贝构造函数。在c语言中,

    int a = 5;  //初始化
    int b;
    b = 6;      //赋值
    

    上面的初始化及赋值操作是最正常不过的语法,c++语言肩挑兼容c语言语法的责任,所以在类的设计上,也兼容这种操作:

    class cls{
    pubic:
    
        //...
        
    }
    int main(void)
    {
        cls c1;
        cls c2 = c1;    //初始化类,还可以 cls c2(c1);
        cls c3;
        c3 = c1;        //赋值类
    
        //...
    
        return 0;
    }
    
    展开全文
  • 以下情况会调用拷贝构造函数 1.直接初始化和拷贝初始化时 2.将一个对象作为实参传递给一个非引用或非指针类型的形参时 3.从一个返回类型为非引用或非指针的函数返回一个对象时 4.用花括号列表初始化一个...

    以下情况会调用拷贝构造函数

    1.直接初始化和拷贝初始化时

    2.将一个对象作为实参传递给一个非引用或非指针类型的形参时

    3.从一个返回类型为非引用或非指针的函数返回一个对象时

    4.用花括号列表初始化一个数组的元素或者一个聚合类(很少使用)中的成员时。

    展开全文
  • 一、背景介绍 因为工作关系,需要用到C++...对于复制构造函数、重载操作符、智能指针等概念,虽然也时有接触,但真正自己写代码需要用到的时候,并不多。 本文尝试对复制构造函数的定义、作用及需要注意的地方做...

    一、背景介绍

              因为工作关系,需要用到C++编程。对于我来说,虽然一直从事的是linux平台下的嵌入式软件开发,但深入用到C++的特性的地方并不多。对于C++,用得最多的无非是指针、封装、继承、组合以及虚函数。对于复制构造函数、重载操作符、智能指针等概念,虽然也时有接触,但真正自己写代码需要用到的时候,并不多。

              本文尝试对复制构造函数的定义、作用及需要注意的地方做一个简单的解剖。希望能抛砖引玉,对大家的学习起到一个帮助作用。

               虽然复制构造函数对于基本的C++编程来说,可能不太用得着。不过这并不说明复制构造函数没什么用,其实复制构造函数能解决一些我们常常会忽略的问题。

                假设有一个CStudent类,有数据成员char* name;

                现在有一个对象CStudent stu1("tom");//数据成员name="tom";

                再生成一对象,stu2,把stu1拷贝给stu2,即CStudent stu2(stu1);

                如果我们没有写拷贝构造函数,那么编译器会调用默认的拷贝构造函数.即进行浅拷贝.

    浅拷贝的意思就是内存中只有一份"tom",对象stu1的name指针指向了它.把stu1拷贝给stu2后,stu2的name指向也指向了"tom",指向的是内存中同一块地址.这就会出现一个问题:当stu1的对象被销毁了,那么stu1的name指向的"tom"也会被销毁,由于stu2中的name也是指向"tom"的,所以这时stu2中的name就变成空的了,甚至是乱码.

               如果我们自己写了拷贝构造函数,那么在内存中就会有两份"tom"了,这时stu1的name和stu2的name就没有什么关系了,只不过他们的值都是"tom"而已!

               类似的问题,我们看看如下代码,并编译运行看看结果:

    [cpp]  view plain  copy
    1. #include <iostream>  
    2.    
    3. class Array {  
    4. public:  
    5.     int size;  
    6.     int* data;  
    7.    
    8.     implicit Array(int size)   
    9.         : size(size), data(new int[size])  
    10.     {  
    11.     }  
    12.    
    13.     ~Array()   
    14.     {  
    15.         delete[] this->data;  
    16.     }  
    17. };  
    18.    
    19. int main()   
    20. {  
    21.     Array first(20);  
    22.     first.data[0] = 25;  
    23.    
    24.     {  
    25.         Array copy = first;  
    26.         std::cout << first.data[0] << " " << copy.data[0] << std::endl;  
    27.     }    // (1)  
    28.    
    29.     first.data[0] = 10;    // (2)  
    30. }  


    运行结果:

    25 25

    Segmentation fault

    为什么会出现segmentation fault段错误这么严重的问题呢?

    根本原因跟前面那个例子一样,我们没有写拷贝构造函数。因此,编译器会为我们生成一个默认的拷贝构造函数。默认的构造函数形式如下:

    [cpp]  view plain  copy
    1. Array(const Array& other)  
    2.   : size(other.size), data(other.data) {}  

    该默认构造函数有什么问题呢?

    它对data 指针执行的是浅拷贝。也就是说,它只是拷贝原始data成员的地址,这样就带来了两个对象共享指向同一块内存的指针的风险。代码执行到main函数(1)处时,即执行到:

    [cpp]  view plain  copy
    1. {  
    2.     Array copy = first;  
    3.     std::cout << first.data[0] << " " << copy.data[0] << std::endl;  
    4. }    // (1)  


    (1)处时,copy的析构函数会被调用,因为分配在stack上的对象,是自动释放的。当我们进入一个特定的作用域时,堆栈指针会向下移动一个单位,为那个作用域内创建的、以堆栈为基础的所有对象分配存储空间。而当我们离开作用域的时候(调用完毕所有局部构建器后),堆栈指针会向上移动一个单位,也就是copy对象的析构函数在执行到(1)处后会自动得到调用。Array的析构函数,删除了copy的data.由于first和copy对象都共享一个data指针,因此当执行到(2)处,即调用first.data[0]=10时,就会产生令人头痛的段错误::segmentation fault.

    如何解决这个问题呢?

    写一个自己的拷贝构造函数,并执行深拷贝

    [cpp]  view plain  copy
    1. // for std::copy  
    2. #include <algorithm>  
    3.    
    4. Array(const Array& other)  
    5.     : size(other.size), data(new int[other.size])   
    6. {  
    7.     std::copy(other.data, other.data + other.size, data);   
    8. }  

    二、浅拷贝与深拷贝

    浅拷贝:仅仅逐个成员拷贝,而不拷贝资源的方式;浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。举个例子,一个人一开始叫张三,后来改名叫李四了,可是还是同一个人,不管是张三缺胳膊少腿还是李四缺胳膊少腿,都是这个人倒霉。比较典型的就有Reference(引用)对象,如Class(类)。

    深拷贝:既拷贝成员,又拷贝资源的方式。深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等。

    系统提供的默认拷贝构造函数为浅拷贝,深拷贝必须自己定义。

    这也解释了背景中的段错误原因及为什么要自己写拷贝构造函数.


    三、什么是拷贝构造函数

    拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的参数(对象的引用)是不可变的(const类型)。也就是说,当用一个已经存在的对象为一个新的对象进行赋值时,首先要给新对象的数据成员分配空间资源以创建新对象,然后用源对象的成员值进行初始化。这个行为必须在对象构造的时候进行完成,而普通的构造函数无法完成这项工作,因此拷贝构造函数应运而生!

    在C++中,下面三种对象需要拷贝的情况。因此,拷贝构造函数将会被调用。
      1). 一个对象以值传递的方式传入函数体
      2). 一个对象以值传递的方式从函数返回
      3). 一个对象需要通过另外一个对象进行初始化搜索
      以上的情况需要拷贝构造函数的调用。如果在前两种情况不使用拷贝构造函数的时候,就会导致一个指针指向已经被删除的内存空间。对于第三种情况来说,初始化和赋值的不同含义是构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值操作赋共同实现的。

    拷贝构造函数的标准写法如下:


    class  Base

        public:

           Base(){}  
           Base( const Base &b){..}  //拷贝构造函数的参数必须是该对象的引用

    }

     进一步总结:

    1) 拷贝构造函数的作用就是用来复制对象的,在使用这个对象的实例来初始化这个对象的一个新的实例。
    2)如果不显式声明拷贝构造函数的时候,编译器也会生成一个默认的拷贝构造函数,只执行浅拷贝在一般的情况下,浅拷贝运行的也很好。

    但是在遇到类有指针数据成员时就出现问题了:因为默认的拷贝构造函数是按成员拷贝构造,这导致了两个不同的指针(如ptr1=ptr2)指向了相同的 内存。当一个实例销毁时,调用析构函数free(ptr1)释放了这段内存,那么剩下的一个实例的指针ptr2就无效了,在被销毁的时候free(ptr2)就会出现错误了, 这相当于重复释放
    一块内存两次。这种情况必须显式声明并实现自己的拷贝构造函数,来为新的实例的指针分配新的内存。

    展开全文
  • 一、默认拷贝构造函数、浅拷贝 当对一个已知对象进行拷贝时,编译系统会自动调用一种构造函数 —— 拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数。 #include <iostream> using ...

    一、默认拷贝构造函数、浅拷贝

            当对一个已知对象进行拷贝时,编译系统会自动调用一种构造函数 —— 拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数

    #include <iostream>  
    using namespace std;
     
    class Student
    {
    private:
        int num;
        char *name;   //此处类中包含指针
    public:
        Student();
        ~Student();
    };
     
    Student::Student()
    {
        name = new char(20);
        cout << "Student" << endl;
     
    }
    Student::~Student()
    {
        cout << "~Student " << (int)name << endl;
        delete name;
        name = NULL;
    }
     
    int main()
    {
        {// 花括号让s1和s2变成局部对象,方便测试
            Student s1;
            Student s2(s1);// 复制对象
        }
        system("pause");
        return 0;
    }

            执行结果:调用一次构造函数,调用两次析构函数,两个对象的指针成员所指同一块内存,这会导致什么问题呢?name指针被分配一次内存,但是程序结束时该内存却被释放了两次,会导致崩溃!

            由于编译系统在我们没有自己定义拷贝构造函数时,会在拷贝对象时调用默认拷贝构造函数,进行的是浅拷贝!即对指针name拷贝后会出现两个指针指向同一个内存空间。

    二、自定义拷贝构造函数、深拷贝

            所以,在对含有指针成员的对象进行拷贝时,必须要自己定义拷贝构造函数,使拷贝后的对象指针成员有自己的内存空间,即进行深拷贝,这样就避免了内存泄漏发生。

            //自己定义构造函数,进行深拷贝

    Student::Student(const Student &s)
    {
        name = new char(20);
        memcpy(name, s.name, strlen(s.name));  
        cout << "copy Student" << endl;
    }

            执行结果:调用一次构造函数,一次自定义拷贝构造函数,两次析构函数。两个对象的指针成员所指内存不同。

    三、浅拷贝、深拷贝

    1、浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间。

    2、深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

    四、浅拷贝带来的问题

    1、两个对象的指针成员可能指向相同的内存相互影响

    2、对其中一个指针进行释放操作或销毁析构,将导致另一个指针成为 “悬空指针”。

     

    参考链接

    https://blog.csdn.net/chen1234520nnn/article/details/83338990

    展开全文
  • c++默认拷贝构造函数,从深度拷贝和浅拷贝说起

    万次阅读 多人点赞 2017-07-24 19:44:10
    1. c++类的默认拷贝构造函数的弊端c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于: (1)当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且其函数体为空;...
  • 1.c++默认拷贝构造函数,从深度拷贝和浅拷贝说起 c++类的默认拷贝构造函数的弊端 c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于: (1)当类中没有定义任何构造函数时,...
  • c++中,当我们定义一个类的时候,如果我们什么都不定义的时候,c++编译器会默认的为我们生成一些函数。 例如定义一个Example类。 class Example{ }; ...当我们定义一个Example类的... 拷贝构造函数Example(const Exa
  • C++提供了默认拷贝构造函数: class C { private: int a; public: C(const C& c) {a = c.a;} }默认的拷贝构造函数是将类中的成员全部复制一遍,但是当类中的成员为指针一类的资源时,拷贝的是指针本身,而资源...
  • (3)复制(拷贝构造函数 Student(Student&);//形参是本类对象的引用 (4)转换构造函数 Student(int r) ;//形参时其他类型变量,且只有一个形参 默认和初始化构造函数 默认构造函数和初始化构造函数在定义...
  • 前两者会在创建一个类实例的时候被调用,而最后的拷贝赋值函数是对一个已经创建的实力进行=调用的时候被调用。 拷贝赋值函数的返回值应该为该类的一个引用,否则无法使用classA = classB = classC。 Show me the ...
  • 概述使用 class object 时,在以下三种情况会以一个 object 的内容作为另一个 class object 的初值,即用到拷贝构造函数: ...若用户没有显示声明或定义拷贝构造函数,则 C++ 在 必要 时为 class 声明或定义隐式拷贝
  • C++ | 拷贝构造函数 与 赋值运算符

    千次阅读 2019-02-24 23:48:37
    文章目录引言拷贝构造函数和赋值运算符区别拷贝构造函数何时调用拷贝构造函数默认拷贝构造函数的功能定义一个显式拷贝构造函数以解决问题赋值运算符赋值运算符的功能及何时使用它解决赋值的问题在构造函数中使用new...
  • 而构造函数又分为默认构造函数、拷贝构造函数和自定义的构造函数。 构造函数 1、构造函数必须与类同名。 2、C++允许构造函数重载。 3、构造函数没有返回值。 默认构造函数 不带参数的 构造函数 就是 默认构造...
  • 参考:C++ 拷贝构造函数和赋值构造函数 一、简单说明 在C++中,如果我们定义一个空类,编译器会默认为我们自动生成以下四个函数: 1、默认构造函数 2、析构函数 3、拷贝构造函数 4、赋值构造函数。通常情况下,我们...
  • C++编译器合成默认构造函数的条件
  • C++拷贝构造函数详解

    万次阅读 多人点赞 2011-02-23 13:39:00
    什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。 下面看一个类对象...
  • 构造函数可以有多个,而拷贝构造函数只能有一个,因为拷贝构造函数的参数只能是当前类的一个对象,参数表是固定的,无法重载,若用户没有定义自己的辅助构造函数,系统会自动生成一个复制构造函数(浅拷贝构造函数,...
  • C++拷贝构造函数

    2014-10-16 11:58:22
    拷贝构造函数主要需要考虑两个问题:一个是什么时候会调用拷贝构造函数,另一个是
  • C++ 拷贝构造函数 深拷贝 浅拷贝
  • 对象有时是被自动复制的。自动复制发生在对对象作出以下操作时: (1)通过值传递给函数 (2)从函数返回 (3)通过初始式初始化为另一个对象 ...默认拷贝构造函数只是简单的将每个数据成员的值复制给新对象
  • 如题,请解释一次详细的原理 假如我定义一个类的对象a,然后在没有自己编写构造函数的情况下用语句A b=a来初始化新的对象b,会发生什么,为什么?
  • c++默认拷贝构造函数---浅复制

    千次阅读 2016-01-25 15:12:42
    默认拷贝构造函数是浅复制,比如如下程序,类中指向的地址是一样的#include using namespace std;class Test { public: int *a; };int main() { Test *t = new Test(); int aa = 1314520; t->a = &aa; ...
  • 在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝是可行的。 但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个...
  • 当我们显式或者隐式地对该类型进行拷贝操作时,就会用到该类的拷贝构造函数(copy construction)和拷贝赋值操作符(copy-assignment operator)。 1 拷贝构造函数 如果一个构造函数的第一个参数是自身类类型的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 70,395
精华内容 28,158
关键字:

c++默认拷贝构造函数

c++ 订阅