精华内容
下载资源
问答
  • C++拷贝构造函数调用时机及陷阱

    千次阅读 2018-06-28 12:01:41
    拷贝构造调用有四种 用一个对象 初始化 另一个对象时 函数实参传递给形参时,这也差不多是初始化啦 函数返回值,C++编译器在这做的就很奇怪了,今天早上调了一早上 #define _CRT_SECURE_NO_WARNINGS #include &...

    拷贝构造调用有四种

    1. 用一个对象 初始化 另一个对象时
    2. 函数实参传递给形参时,这也差不多是初始化啦
    3. 函数返回值,C++编译器在这做的就很奇怪了,今天早上调了一早上
    #define _CRT_SECURE_NO_WARNINGS
    
    #include <iostream>
    
    using namespace std;
    
    //大家可以看一下陷阱在哪
    class Teacher
    {
    public:
        Teacher(char *name, int age)
        {
            this->name_len = strlen(name);
            this->name = new char[name_len + 1];
            strcpy(this->name, name);
            this->age = age;
        }
        Teacher(const Teacher &obj)
        {
            cout << "调用了copy构造函数... " << endl;
            if (obj.name_len < 0)
            {
                return;
            }
            if (name != NULL) //
            {
                delete[] name;
                name = NULL;
            }
            name_len = obj.name_len;
            name = new char[name_len + 1];
            strcpy(name, obj.name);
            age = obj.age;
        }
    public:
        char* name; //姓名
        int name_len; //姓名的长度
        int age; //年龄
    };
    • 看着好像是问题不大,我们来运行一下
    void main()
    {
        Teacher t1("calf", 50);
        cout << t1.age << t1.name << endl;
    
        Teacher t2("aaaa", 15);
        cout << t2.age << t2.name << endl;
    
        Teacher t3 = t1;
        cout << t3.age << t3.name << endl;
    }

    这里写图片描述
    ok,运行成功
    - 然后我们开始测试函数返回值调用的copy构造函数

    //先写个函数
    Teacher getT()
    {
        Teacher tmp("young", 12);
        return tmp;
    }
    //调用试试
    void main()
    {
        Teacher t1("calf", 50);
        cout << t1.age << t1.name << endl;
    
        Teacher t2("aaaa", 15);
        cout << t2.age << t2.name << endl;
    
        Teacher t3 = t1; //加了这四行
        cout << t3.age << t3.name << endl;  
        t3 = getT(); 
        cout << t3.age << t3.name << endl;
    }

    这里写图片描述
    执行到这就宕机了,,,
    这里写图片描述
    通过调试,发现拷贝构造函数里去掉这几行就行了

    Teacher(const Teacher &obj)
        {
            cout << "调用了copy构造函数... " << endl;
            if (obj.name_len < 0)
            {
                return;
            }
            /*这几行
            if (name != NULL) //
            {
                delete[] name;
                name = NULL;
            }
            */
            name_len = obj.name_len;
            name = new char[name_len + 1];
            strcpy(name, obj.name);
            age = obj.age;
        }

    查了些资料,原因如下:
    在执行这句的时候 t3 = getT(); , 会产生一个匿名对象(就是没有任何调用的对象),会先把getT()函数的tmp对象通过copy构造函数,初始化这个匿名对象,然后析构这个tmp对象完成退出这个函数,然后通过等号操作符(可以重载)把产生的匿名对象赋给t3,再析构这个匿名对象。
    这里写图片描述

    • 现在开始说我们的陷阱了,个人觉得宕机的原因: C++除了全局变量以外的变量都不会自动赋初值,即我们Teacher类的char *name的初始值是随机的,匿名对象的name值不为空,故析构了还没分配内存的name野指针。

    ps:C++博大精深,觉得这个解析可能也不是很合理,望指点。

    展开全文
  • class A { public :A(int a) { b=a; c++; cout()"; } A() { c++; cout; } A(const A&a) { this->
    class A
    {
    
    public :A(int a)
    		{
    			b=a;
    			c++;
    			cout<<"construct A()"<<b<<"c"<<c<<endl;
    
    		}
    		A()
    		{
    			c++;
    			cout<<"non argument method"<<b<<"c"<<c<<endl;
    			
    
    		}
    		A(const A&a)
    		{
    			this->b=a.b;
    			c++;
    			cout<<"copy construct method"<<b<<"c"<<c<<endl;
    		}
    		~A()
    		{
    			c--;
    			cout<<"destroy method"<<b<<"c"<<c<<endl;
    			
    		}
    		int b;
    		static int c;
    
    };
    int A::c=0;
    
    class B
    {
    private: A a;
    public:
    	B(A a)
    	{
    		cout<<"here"<<endl;
    		this->a=a;
    		cout<<"here1"<<endl;
    	}
    
    };
    A g();
    int main()
    {
    	A a=g();
    	cout<<"asd"<<endl;
    	system("pause");
    }
    A g()
    {
    	A a=A(2);
    	
    	cout<<"here"<<endl;
    	A c=a;
    	cout<<"here1"<<endl;
    	return NULL;
    	//B b=B(a);
    	//return a;
    
    }


    结果
    construct A()2c1
    here
    copy construct method2c2
    here1
    construct A()0c3
    destroy method2c2
    destroy method2c1
    asd
    请按任意键继续. . .
    


    1程序首先进入到函数g里面,先调用A的有参构造;

    2 A c=a; 这一段调用A的拷贝构造函数,没有异议。 如果将程序改为   A c;  c=a;  程序将不会调用拷贝构造函数,而是调用系统默认的=操作符。

    3 函数有返回值,并且返回值为值对象,所以调用默认


    将程序的返回值改为 return a;

    结果

    construct A()2c1
    here
    copy construct method2c2
    here1
    copy construct method2c3
    destroy method2c2
    destroy method2c1
    asd
    请按任意键继续. . .

    函数返回时程序调用A的拷贝构造函数(其中这个拷贝函数的参数为a)产生一个临时对象,该临时对象有个指针指向这个对象,该指针存储在寄存器中,当函数的堆栈销毁了,但是里面的值并没有擦除,所以依然可以借助这个寄存器的指针得到函数返回的这个临时对象的值。函数结束时先要销毁c对象(因为为自动变量存储在堆栈中先进后出原则),然后销毁a,最后函数执行完,再去销毁函数返回时调用拷贝构造函数产生的临时对象。如果你返回的Null则调用的会是普通的单个参数为int 型1的构造函数,如果没有程序则会报错。(如果你没有一个并且只有一个参数为int 的构造函数,系统尝试调用默认的拷贝构造函数,调用过程中会出现类型转换错误,将值1(null)转为const & xxx)。

    如果函数返回的对象在调用的地方有存储(即上例中在main函数中 A a=g())则所谓的函数返回时创建的临时对象其实不是临时对象而是一个在main结束才释放的对象。


    如果一个对象先声明(一般的声明和定义在同一语句中),在做赋值的话那么它将不会调用拷贝构造函数。即在对象的初始化中才会调用拷贝构造函数。


    展开全文
  • 先看代码: #include class B { int data; public: B(int a) : data(a) { std::cout << 111111 << std::endl; } B(const B &b) { data = b.data; std::cout << 222222 <... sys
  • C++拷贝构造函数调用的时机

    千次阅读 多人点赞 2017-07-28 17:41:59
    拷贝构造函数调用的几种情况: 1. 当用类的一个对象去初始化该类的另一个对象(或引用)时系统自动调用拷贝构造函数实现拷贝赋值。 2. 若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造...

    拷贝构造函数调用的几种情况:

    1. 当用类的一个对象去初始化该类的另一个对象(或引用)时系统自动调用拷贝构造函数实现拷贝赋值。
    2. 若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数。(这里可有可能被编译器优化)
    3. 当函数的返回值是类对象时,系统自动调用拷贝构造函数。(注意会有编译器可能会进行优化,而观察不到拷贝的发生)
    #include<ctime>
    #include<cstdlib>
    #include<iterator>
    #include<algorithm>
    #include<iostream>
    #include<numeric>
    using namespace std;
    
    class A {
    public:
    	A():data(0){}
    	A(const A& a){
    		data = a.data;
    		cout << "拷贝构造函数调用\n";
    	}
    	A& operator=(const A&a){
    		data = a.data;
    		cout << "调用赋值函数\n";
    		return *this;
    	}
    
    	int data;
    };
    
    void fun1(A a) {
    	return ;
    }
    
    A fun2() {
    	A a;
    	return a;
    }
    
    int main() {
    	A a;
    	A b(a);          //用类的一个对象a去初始化另一个对象b
    	A c = a;         //用类的一个对象a去初始化另一个对象c,注意这里是初始化,不是赋值
    	fun1(a);         //形参为类对象,实参初始化形参,调用拷贝构造函数。
    	A d = fun2();    //函数返回一个类对象时, 这里可能会被编译器优化,从而可能没有调用拷贝构造
    	d = a;           //d已经初始化过了,这里是赋值,调用赋值函数
    
    	return 0;
    }
    

    需要注意,在第三条:当函数的返回值是类对象时,系统自动调用拷贝构造函数。这里默认情况下一般会被编译器优化,减少不必要的拷贝构造,所以,具体的返回值可能会因编译器及编译选项的不同而不同。使用g++编译器,关闭优化g++ xxx.cpp -fno-elide-constructors后执行结果如下(-fno-elide-constructors选项就是用来关闭拷贝优化的):

    拷贝构造函数调用
    拷贝构造函数调用
    拷贝构造函数调用
    拷贝构造函数调用
    拷贝构造函数调用
    调用赋值函数
    

    默认情况下,优化后的结果如下:

    拷贝构造函数调用
    拷贝构造函数调用
    拷贝构造函数调用
    调用赋值函数
    

    编译器具体是怎么优化的,一般编译器会先看支不支持拷贝优化,如果不支持,再看有没有定义移动构造函数,如果都没有,就调用拷贝构造函数。更具体的细节可以参考移动语义及拷贝优化的内容。

    最后,注意A c=a;d=a;的不同,一个是初始化,一个是赋值。

    欢迎关注公众号【一日思考】,学而不思则罔,思而不学则殆!
    在这里插入图片描述

    展开全文
  • C++拷贝构造函数调用时机

    千次阅读 2019-02-21 22:41:00
    C++拷贝构造函数的调用时机 一、拷贝构造函数调用的时机 ​ 当以拷贝的方式初始化对象时会调用拷贝构造函数,这里需要注意两个关键点,分别是以拷贝的方式和初始化对象 1. 初始化对象 初始化对象是...

    C++拷贝构造函数的调用时机

    一、拷贝构造函数调用的时机

    ​ 当以拷贝的方式初始化对象时会调用拷贝构造函数,这里需要注意两个关键点,分别是以拷贝的方式初始化对象

    1. 初始化对象

    初始化对象是指,为对象分配内存后第一次向内存中填充数据,这个过程会调用构造函数,对象被创建后必须立即初始化。也就是说只要创建对象就会调用构造函数。

    2.初始化和赋值的区别

    初始化和赋值都是将数据写入内存中,从表面看,初始化在很多时候都是以复制的方式来实现的,很容易引起混淆。在定义的同时进行复制叫做初始化,定义完成以后再赋值(不管定义的时候有没有赋值)就叫做赋值。初始化只能由一次,赋值可以由很多次。具体可以看下面的示例。

    int a = 100;  //以赋值的方式初始化
    a = 200;  //赋值
    a = 300;  //赋值
    int b;  //默认初始化
    b = 29;  //赋值
    b = 39;  //赋值

    ​ 对于基本的数据类型,我们很少会区分初始化和赋值,即使是混淆了,也不会出现什么错误。但是对于类,他们的区别就非常重要了,因为初始化时会调用构造函数(以拷贝的方式初始化时会调用拷贝构造函数),而赋值时会调用重载过的赋值运算符。

    二、拷贝构造函数和普通构造函数调用的例子

    #include<iostream>
    #include<string>
    
    using namespace std;
    
    class Student {
    public:
        Student(string name = "", int age = 0); //普通构造函数
        Student(const Student &Stu); //拷贝构造函数
        Student& operator=(const Student &Stu); // 重载 = 运算符
        void display();
        
    
    private:
        string m_name;
        int m_age;
    
    };
    
    //普通构造函数
    Student::Student(string name , int age )
    {
        m_name = name;
        m_age = age;
    }
    
    //拷贝构造函数
    Student::Student(const Student &Stu)
    {
        this->m_name = Stu.m_name;
        this->m_age = Stu.m_age;
    
        cout << "Copy constructor was called." << endl;
    }
    
    // 重载 = 运算符
    Student& Student:: operator=(const Student &Stu)
    {
        this->m_name = Stu.m_name;
        this->m_age = Stu.m_age;
    
        cout << "operator=() was called." << endl;
    
        return *this;
    }
    
    void Student::display()
    {
        cout << m_age << "  " << m_age << endl;
    }
    
    
    int main()
    {
        Student stu1("Xiao Ming", 18);  // 调用普通构造函数
        Student stu2("Xiao Wang", 18);  // 调用普通构造函数
    
        Student stu3 = stu1;  // 调用拷贝构造函数
        stu3 = stu2;  //调用operator=()
    
        Student stu4(stu1);   // 调用拷贝构造函数
    
        Student stu5; // 调用普通构造函数
        stu5 = stu2;  //调用operator=()
    
        return 0;
    }
    
    /*
    输出:
        Copy constructor was called.
        operator=() was called.
        Copy constructor was called.
        operator=() was called.
    
    
    */

    三、以拷贝的方式初始化对象

    1. 初始化对象时会调用构造函数,不同的初始化方式会调用不同的构造函数:
    • 如果用传递进来的实参初始化对象,那么会调用普通的构造函数。
    • 如果用现有对象的数据来初始化对象,就会调用拷贝构造函数,这就是以拷贝的方式初始化对象。
    2. 以拷贝的方式来初始化对象的几种情况:
    1. 将其它对象作为实参。

      Student stu1("Xiao Ming", 18);  // 普通初始化
      Student stu4(stu1);   // 以拷贝的方式进行初始化
      /* 即使我们不在类中显示定义拷贝构造函数,这种初始化方式也是有效的,编译器会生成默认的拷贝构造函数 */
    2. 在创建对象的同时赋值。

      Student stu1("Xiao Ming", 18);  // 普通初始化
      Student stu3 = stu1;  // 以拷贝的方式进行初始化
      /* 这是最常见的一种以拷贝的方式初始化对象的情况 */
    3. 函数的形参为类类型。

      如果函数的形参为类类型(对象),那么调用函数时要将另外一个对象作为实参传递进来赋值给形参,这也是以拷贝的方式初始化形参对象,如下所示。

      void func(Student s){
          //TODO:
      }
      Student stu1("Xiao Ming", 18);  // 普通初始化
      func(stu1);  //以拷贝的方式初始化
      
      /* func() 函数有一个 Student 类型的形参 s,将实参 stu 传递给形参 s 就是以拷贝的方式初始化的过程。 */
    4. 函数返回值为类类型(与编译器有关不绝对)

      ​ 当函数的返回值为类类型时,return 语句会返回一个对象,不过为了防止局部对象被销毁,也为了防止通过返回值修改原来的局部对象,编译器并不会直接返回这个对象,而是根据这个对象先创建出一个临时对象(匿名对象),再将这个临时对象返回。而创建临时对象的过程,就是以拷贝的方式进行的,会调用拷贝构造函数,如下所示。

      Student func(){
         Student stu1("Xiao Ming", 18);  // 普通初始化
          return stu1;
      }
      Student stu = func();
    posted @ 2019-02-21 22:41 ay-a 阅读( ...) 评论( ...) 编辑 收藏
    展开全文
  • C++拷贝构造函数详解

    万次阅读 多人点赞 2011-02-23 13:39:00
    什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。 下面看一个类对象...
  • C++提供的默认拷贝构造函数工作的方法是:完成一个成员一个成员的拷贝,如果成员是类对象,则调用拷贝构造函数或者默认拷贝构造函数。   而拷贝构造函数和赋值运算符则是C++独有的,也是很多人所不熟悉的地方。...
  • 以下情况会调用拷贝构造函数 1.直接初始化和拷贝初始化时 2.将一个对象作为实参传递给一个非引用或非指针类型的形参时 3.从一个返回类型为非引用或非指针的函数返回一个对象时 4.用花括号列表初始化一个...
  • C++拷贝构造函数调用的三种情况

    千次阅读 2013-05-24 10:54:34
    C++拷贝构造函数调用的三种情况 一,当用类的一个对象去初始化该类的另一个对象时: int main() { Point A(1,2); Point B(A); //用对象A初始化对象B,拷贝构造函数被调用 cout () ; return 0; }
  • C++中,下面三种对象需要调用拷贝构造函数! 1. 对象以值传递的方式传入函数参数 2. 对象以值传递的方式从函数返回 3. 对象需要通过另外一个对象进行初始化; 本人只是做个备案自己学习、详细可以参考...
  • 在进入派生类(derived)的拷贝构造函数之前,就已经调用了基类(based)的构造函数, 无论你有没有显示的调用。 一般派生类是这种形式: derived(const derived & d):based(d) {} 为什么使用下列形式不行 ...
  • 本篇文章是对C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程进行了总结与分析,需要的朋友参考下
  • C++ 拷贝构造函数的四种调用时机

    千次阅读 多人点赞 2018-08-13 14:55:34
    拷贝构造函数的调用有四种场景 假设定义了一个类A: class A { public: A(const A&...第一种copy构造函数调用: void main() { A a1; A a2 = a1;//调用copy构造函数 a2 = a1;//浅cop...
  • 一个经常发生的和继承有关的类似问题是在实现派生类的拷贝构造函数时。看看下面这个构造函数:www.huaqiangu6.comclassbase{public:base(intinitialvalue=0):x(initialvalue){}base(constbase&rhs):x(rhs.x){}...
  • c++拷贝构造函数

    千次阅读 多人点赞 2019-06-28 16:22:40
    什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。 下面看一个类对象...
  • C++ 拷贝构造函数 深拷贝 浅拷贝
  • 本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数、什么情况下调用赋值运算符。最后,简单的分析了下深拷贝和浅拷贝的问题。有需要的朋友可以看下
  • C++拷贝构造函数和赋值操作 拷贝构造函数对同一个对象来说只会调用一次,而且是在对象构造时调用。此时对象本身还没有构造,无需要去释放自己的一些资源。而赋值操作可能会调用多次,你在拷贝之前要释放自己的一些...
  • C++:派生类的默认构造函数和拷贝构造函数调用基类构造函数的机制(含程序验证) 1、如果基类定义了不带参数的默认构造函数,则编译器为派生类自动生成的默认构造函数会调用基类的默认构造函数。 2、如果基类定义...
  • 这里我们用类String 来介绍这两个函数: ...试想一下,假如形参是该类的一个实例,由于是传值参数,我们把形参复制到实参会调用拷贝构造函数,如果允许拷贝构造函数传值,就会在拷贝构造函数调用拷贝构...
  • c++拷贝构造函数是形如User(const User & user)的函数,看起来与构造函数类似,没有返回类型,但是其参数一定要是不可修改的引用类型,即参数是被拷贝的对象,不可修改 同时,拷贝构造函数也是构造函数的一个特例...
  • 构造函数可以有多个,而拷贝构造函数只能有一个,因为拷贝构造函数的参数只能是当前类的一个对象,参数表是固定的,无法重载,若用户没有定义自己的辅助构造函数,系统会自动生成一个复制构造函数(浅拷贝构造函数,...
  • C++ 拷贝构造函数和赋值构造函数

    万次阅读 多人点赞 2019-04-06 16:43:35
    C++中复制控制是一个比较重要的话题,主要包括复制构造函数、重载赋值操作符、析构函数这三部分,这三个函数是一致的,如果类需要析构函数,则它也需要复制操作符 和 复制构造函数,这个规则被称为 C++的“三法则...
  • 本文前面主要介绍了拷贝构造函数和赋值运算符函数的区别,以及在什么时候调用拷贝构造函数、什么情况下调用赋值运算符函数。最后,分析了下深拷贝和浅拷贝的问题,即拷贝构造函数和赋值运算符函数的必要性和意义。...
  • C++ 拷贝构造函数

    千次阅读 2014-05-24 16:27:10
    拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的形参必须是引用,但并不限制为const,一般普遍的会加上const限制。此函数经常用在函数调用时用户定义...
  • C++ 拷贝构造函数 赋值构造函数 拷贝构造函数和赋值构造函数的异同 由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数有些轻视。请先记住以下的警告,在阅读正文时就会多心:如果不...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 101,680
精华内容 40,672
关键字:

c++拷贝构造函数调用

c++ 订阅