精华内容
下载资源
问答
  • 2021-04-13 14:17:26

    移动构造函数是c++11的新特性,移动构造函数传入的参数是一个右值 用&&标出。一般来说左值可以通过使用std:move方法强制转换为右值。

    拷贝构造函数:拷贝构造函数是先将传入的参数对象进行一次深拷贝,再传给新对象。这就会有一次拷贝对象的开销,并且进行了深拷贝,就需要给对象分配地址空间。

    而移动构造函数就是为了解决这个拷贝开销而产生的。

    移动构造函数:首先将传递参数的内存地址空间接管,然后将内部所有指针设置为nullptr,并且在原地址上进行新对象的构造,最后调用原对象的的析构函数,这样做既不会产生额外的拷贝开销,也不会给新对象分配内存空间。

    而对于指针参数来讲,需要注意的是,移动构造函数是对传递参数进行一次浅拷贝。也就是说如果参数为指针变量,进行拷贝之后将会有两个指针指向同一地址空间,这个时候如果前一个指针对象进行了析构,则后一个指针将会变成野指针,从而引发错误。所以当变量是指针的时候,要将指针置为空,这样在调用析构函数的时候会进行判断指针是否为空,如果为空则不回收指针的地址空间,这样就不会释放掉前一个指针。

    更多相关内容
  • C++移动拷贝构造函数

    2021-10-16 12:28:03
    C++ 移动拷贝构造函数 1.什么是构造函数 “写在前面:文章中用的编译环境是windows下的vs 2019” 概念引入 有时在我们写代码的时候会忘记对数据进行初始化,在c++的类中,构造函数是一种特殊的成员函数,在每次创建...

    移动拷贝构造函数

    1.什么是构造函数

    “写在前面:文章中用的编译环境是windows下的vs 2019”

    概念引入

    有时在我们写代码的时候会忘记对数据进行初始化,在c++的类中,构造函数是一种特殊的成员函数,在每次创建创建一个类的时候会默认调用构造函数进行初始化工作。
    构造函数用来完成一些必要的初始化工作,有了构造函数之后,就无需再单独写初始化函数,并且也不必担心忘记调用初始化函数,因为当你的代码中写了构造函数但是在创建对象的时候没有给构造函数传参编译器就会报错提示“类XXXX不存在默然构造函数”。

    概念

    1.名字与类名相同,可以有参数,但是不能有返回值(void也不行)
    2.作用是对对象进行初始化工作,如给成员变量赋值等。
    3.如果定义类时没有写构造函数,系统会生成一个默认的无参构造函数,默认构造函数没有参数,不做任何工作。
    4.如果定义了构造函数,系统不再生成默认的无参构造函数
    5.对象生成时构造函数自动调用,对象一旦生成,不能在其上再次执行构造函数
    6.一个类也可以有多个构造函数,为重载关系

    例子

    #include<iostream>
    using namespace std;
    
    class Myclass
    {
    public:
    	Myclass(int num)
    	{
    		m_num = num;
    	}
    
    	int getNum()
    	{
    		return m_num;
    	}
    private:
    	int m_num;
    };
    
    int main()
    {
    	Myclass class1(100);
    	cout<<class1.getNum();
    
    	return 0;
    }
    

    上述例子定义了一个Myclass()构造函数来设置m_num的值,这样在每次定义对象的时候都必须初始化,解决了用户在写代码的时候忘记初始化的情况。

    2.拷贝构造函数

    首先对于普通类型的对象来说,它们之间的复制是很简单的,例如:

    int a = 100;
    int b = a; 
    

    而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。
    下面看一个类对象拷贝的简单例子。

    #include<iostream>
    using namespace std;
    
    class Myclass
    {
    public:
    	Myclass(int num)
    	{
    		m_num = num;
    	}
    
    	int getNum()
    	{
    		return m_num;
    	}
    private:
    	int m_num;
    };
    
    int main()
    {
    	Myclass class1(100);
    	Myclass class2(class1);
    	cout << class1.getNum() << endl;
    	cout << class2.getNum()<< endl;
    
    	return 0;
    }
    

    可以看到他打印了两次100,系统为对象class2分配了内存并完成了与对象class1的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。

    3.默认构造函数

    如果用户没有定义构造函数,那么编译器会给类提供一个默认的构造函数,但是只要用户自定义了任意一个构造函数,那么编译器就不会提供默认的构造函数。
    每一次定义对象系统都会默认的生成一个无参的默认构造函数,如下。

    class Myclass
    {
    public:
    	Myclass()//系统会默认生成一个不带参数的构造函数
    	{
    		cout<<"hello world"<<endl;
    	}
    };
    int main()
    {
    	Myclass class}
    
    

    在定义对象的时候,系统会自动生成一个无带参数的构造函数但是这里我显示的写出来了,此时运行代码输出 hello world 证明在定义对象的时候确实调用了无参的构造函数,其实不写出来他也会隐式的调用一个无参的构造函数,但是他什么都不干。

    那如果不想编译器自动的生成一个无参的构造函数或想要编译器使用自动生成的无参构造函数呢?

    c++11引入了两个关键字:deletedefault 关键字

    Myclass() = default;//使用系统默认的构造函数
    Myclass() = delete;//禁止使用默认构造函数和拷贝构造函数
    

    4.移动拷贝构造函数

    1.我们用对象class1初始化对象class2,对象class1我们就不在再使用,但是对象class1的空间还在(在析构之前),拷贝构造函数,就是把class1对象的内容复制一份到class2中,那么为什么我们不能直接使用class1属性所指向的空间,然后释放的时候只释放class1的空间并把他指向的那块空间的控制权交给class2,这样就避免了新的空间的分配,大大降低了构造的成本。这就是移动构造函数设计的初衷。
    2.拷贝构造函数中,对于指针,我们一定要采用深拷贝,而移动构造函数中,对于指针,我们采用浅拷贝。浅拷贝之所以危险,是因为两个指针共同指向一片内存空间,若第一个指针将其释放,另一个指针的指向就不合法了,两次释放同一块地址就会产生异常。
    3.移动构造函数的参数和拷贝构造函数不同,拷贝构造函数的参数是一个左值引用,但是移动构造函数的初值是一个右值引用。意味着,移动构造函数的参数是一个右值或者将亡值的引用。也就是说,只用用一个右值,或者将亡值初始化另一个对象的时候,才会调用移动构造函数。而move语句,就是将一个左值变成一个将亡值。

    接下来用一个例子来展示。

    #include<iostream>
    using namespace std;
    
    class student
    {
    public:
    	student(const char* name)
    	{
    		cout << "contructor student" << endl;
    
    		int len = strlen(name);
    		m_name = new char[len + 1];
    		strcpy_s(m_name, len + 1, name);
    
    	}
    	//拷贝构造函数
    	student(const student& other)
    	{
    		cout << "contructor copy student"<<endl;
    		
    		//this->m_name = other.m_name;//浅拷贝,没有分配内存空间两次析构析构的是同一块空间就会有问题
    		
    		int len = strlen(other.m_name);
    		m_name = new char[len + 1];
    		strcpy_s(this->m_name, len + 1, other.m_name);//深拷贝,分配内存空间 
    		
    	}
    	//移动拷贝构造函数
    	student(student&& other)
    	{
    		cout << "move contructor cpy student" << endl;
    		this->m_name = other.m_name;
    		cout << m_name << endl;
    		other.m_name = nullptr;
    	}
    
    	student()
    	{
    		m_name = nullptr;
    	}
    	
    private:
    	char * m_name;
    };
    
    int main()
    {
    	student stu("zhangsan");
    	//拷贝构造函数
    	student stu3 = stu;//拷贝
    	student sut1(std::move(stu));//移动拷贝构造函数
    	
    	return 0;
    }
    

    调试运行:
    lnosc里插入图片描述
    可以看到创建对象的时候调用了构造函数给m_name赋值并输出输出contructor student
    student stu3 = stu调用了拷贝函数并采用深拷贝给m_name赋值并输出conctruct copy student
    student stu1(std::move(stu))将左值引用改成右值引用并输出“zhangsan”。发生对象移动的前提是要移动的对象之后不再用了,这时就不会调用拷贝构造函数移交控制权给新的对象不发生值的拷贝。

    展开全文
  • 拷贝构造函数2.移动构造函数 1.拷贝构造函数 拷贝构造函数,它是一种特殊的构造函数。它的作用就是用一个已经生成的对象来初始化另一个同类的对象。 当类中拥有指针类型的成员变量时,拷贝构造函数中需要以深拷贝...

    1.拷贝构造函数

    拷贝构造函数,它是一种特殊的构造函数。它的作用就是用一个已经生成的对象来初始化另一个同类的对象。
    当类中拥有指针类型的成员变量时,拷贝构造函数中需要以深拷贝(而非浅拷贝)的方式复制该指针成员。

    浅复制仅仅是指向被复制的内存地址,如果原地址中对象被改变了,那么浅复制出来的对象也会相应改变。深复制在计算机中开辟了一块新的内存地址用于存放复制的对象。

    浅层复制之所以危险,是因为两个指针共同指向一片内存空间,若第一个指针将其释放,另一个指针的指向就不合法了。

    深拷贝:

    #include<iostream>
    using namespace std;
    
    class base {
    public:
        base(int value1,int value2) :p(new int),num(value2) {
            *p = value1;
        }
    
        base(const base& b) :p(new int), num(b.num) {
            *p = *(b.p);
        }//深拷贝
    
        /*base(const base& b) :p(b.p), num(b.num) {}//浅拷贝*/
        void print() {
            cout << "*p=" << *p << "   num=" << num << endl;
        }
        ~base() {
            delete p;
        }
    private:
        int* p;
        int num;
    };
    
    int main()
    {
        base b1(10, 20);
        b1.print();
        base b2(b1);
        b2.print();
        return 0;
    }
    
    *p=10   num=20
    *p=10   num=20
    

    浅拷贝:

    #include<iostream>
    using namespace std;
    
    class base {
    public:
        base(int value1,int value2) :p(new int),num(value2) {
            *p = value1;
        }
    
        /*base(const base& b) :p(new int), num(b.num) {
            *p = *(b.p);
        }//深拷贝*/
    
        base(const base& b) :p(b.p), num(b.num) {}//浅拷贝
        void print() {
            cout << "*p=" << *p << "   num=" << num << endl;
        }
        ~base() {
            delete p;
        }
    private:
        int* p;
        int num;
    };
    
    int main()
    {
        base b1(10, 20);
        b1.print();
        base b2(b1);
        b2.print();
        return 0;
    }
    

    2.移动构造函数

    所谓移动语义,指的就是以移动而非深拷贝的方式初始化含有指针成员的类对象。简单的理解,移动语义指的就是将其他对象(通常是临时对象)拥有的内存资源“移为已用”。

    拷贝构造函数中,对于指针,我们一定要采用深层复制,而移动构造函数中,对于指针,我们采用浅层复制。

    移动构造函数的参数和拷贝构造函数不同,拷贝构造函数的参数是一个左值引用,但是移动构造函数的初值是一个右值引用。意味着,移动构造函数的参数是一个右值或者将亡值的引用。也就是说,只用用一个右值,或者将亡值初始化另一个对象的时候,才会调用移动构造函数。而那个move语句,就是将一个左值变成一个将亡值。

    #include<iostream>
    using namespace std;
    
    class base {
    public:
        base(int value1,int value2) :p(new int),num(value2) {
            *p = value1;
        }
    
        /*base(const base& b) :p(new int), num(b.num) {
            *p = *(b.p);
        }//深拷贝,拷贝构造函数*/
    
        base(base& b) :p(b.p), num(b.num) {
            b.p = NULL;
        }//移动构造函数
        void print() {
            cout << "*p=" << *p << "   num=" << num << endl;
        }
        ~base() {
            delete p;
        }
    private:
        int* p;
        int num;
    };
    
    int main()
    {
        base b1(10, 20);
        b1.print();
        base b2(b1);
        b2.print();
        return 0;
    }
    
    *p=10   num=20
    *p=10   num=20
    
    展开全文
  • 文章目录OOP拷贝构造函数浅拷贝与深拷贝 OOP 拷贝构造函数 A(const A & a); const:防止修改 &:不仅为了节省空间,更为了防止递归!这里是值传递。 #include <iostream> using namespace std; ...

    OOP

    拷贝构造函数

    A(const A & a);

    • const:防止修改
    • &:不仅为了节省空间,更为了防止递归!这里是值传递。
    #include <iostream>
    
    using namespace std;
    class CExample
    {
        int m_nTest;
    public:
    
        CExample(int x):m_nTest(x) //带参数构造函数 使用了初始化表的形式
        {
            cout << "constructor with argument/n";
        }
    
        CExample(const CExample & ex) //拷贝构造函数 不写时有默认拷贝构造函数
        {
            m_nTest = ex.m_nTest;
            cout << "copy constructor/n";
        }
    
        CExample& operator = (const CExample &ex)//赋值函数(赋值运算符重载) 传值
        {
            cout << "assignment operator/n";
            m_nTest = ex.m_nTest;
            return *this;
        }
    
        void myTestFunc(CExample ex)
        {
        }
    };
    
    int main()
    {
        CExample aaa(2);  //constructor with argument
        CExample bbb(3);  //constructor with argument
        bbb = aaa;  //assignment operator  因为bbb已经实例化,不需要构造,只调用赋值函数
        CExample ccc = aaa;  //copy constructor  但是ccc还没有实例化,因此调用的是拷贝构造函数
        bbb.myTestFunc(aaa);  //是aaa作为参数传递给bbb.myTestFunc(CExample ex), 即CExample ex = aaa;和第四个一致,所以还是拷贝构造函数
    
        return 0;
    }  
    

    假如拷贝构造函数参数不是引用类型的话, 则是值传递。由bbb.myTestFunc可知递归的后果。

    使得 ccc.CExample(aaa)变成aaa传值给ccc.CExample(CExample ex),即CExample ex =
    aaa,因为 ex 没有被初始化, 所以 CExample ex = aaa 继续调用拷贝构造函数,接下来的是构造ex,也就是
    ex.CExample(aaa),必然又会有aaa传给CExample(CExample ex), 即 CExample ex =
    aaa;那么又会触发拷贝构造函数,就会永远递归下去。

    什么时候需要自定义拷贝构造函数?深拷贝。

    浅拷贝与深拷贝

    浅拷贝案例:
    如果析构掉s1,abcd也被析构,s2变成悬挂指针(指向的地址不知道存了什么东西),很不好。

    #include <iostream>
    #include <cstring>
    using namespace std;
    class String{
    private:
        char *p;
    public:
        String(char *str){//这是自定义构造函数
            p=new char[strlen(str)+1];
            strcpy(p,str);
        }
        ~String(){
            delete[] p;
        }
    };
    int main() {
        String s1("abcd");
        String s2 = s1;//没有自定义拷贝构造函数,所以默认拷贝构造函数会将指针指向同一空间
        //浅拷贝:s2和s1这两个指针指向堆里的同一空间,再销毁对象时,两个对象的析构函数将同一个内存空间释放两次,这就是错误所在
    }
    

    深拷贝修改:

    #include <iostream>
    #include <cstring>
    using namespace std;
    class String{
    private:
        char *p;
    public:
        String(char *str){//这是自定义构造函数
            p=new char[strlen(str)+1];
            strcpy(p,str);
            cout << "constructor" << endl;
        }
        String(const String & c){//这是自定义拷贝构造函数
            p=new char[strlen(c.p)+1];
            strcpy(p,c.p);
            cout << "copy constructor" << endl;
        }
        ~String(){
            delete[] p;
        }
    };
    int main() {
        String s1("abcd");
        String s2 = s1;//没有实例化,调用自定义拷贝构造函数,所以默认拷贝构造函数会将指针指向同一空间
        //深拷贝:s1和s2各自指向一段内存空间,他们指向的空间具有相同的内容
    //输出内容:
    //constructor
    //copy constructor
    }
    
    易错1:显式调用成员对象的默认构造函数

    自定义拷贝构造函数会调用成员对象的默认构造函数!因为编译器以为你懂!
    ```

    所以程序员需要显式调成员对象的拷贝构造函数!

    #include <iostream>
    using namespace std;
    class A{
    private:
        int x, y;
    public:
        A(){//默认构造函数 注意未提供构造函数时系统才会自动提供
            x=y=0;
        }
        void inc(){
            x++;
            y++;
        }
        void print(){
            cout << " x= " << x << " y= " << y << endl;
        }
    };
    class B{
        int z;
        A a;
    public:
        B(){
            z=0;
        }
    //  这里IDE逼着我对成员变量a进行接管 而没有默认调a的构造函数
    //所以我需要显式调用a的默认拷贝构造函数a(b.a)
        B(const B &b): a(b.a){
            z = b.z;
        }
        void inc(){
            z++;
            a.inc();
        }
        void print(){
            a.print();
            cout << "z= " << z << endl;
        }
    };
    int main() {
        B b1;
        b1.print();//x= 0 y= 0 z= 0
        b1.inc();
        b1.print();//x= 1 y= 1 z= 1
        B b2(b1);
        b2.print();//x= 1 y= 1 z= 1
    }
    
    易错2:NRVO(命名返回值优化)

    而关于ppt上表示拷贝构造函数复杂性,用于引出移动构造函数的例子,经过代码测试并没有2次或3次构造对象,其实只有一次。原因是编译器优化了返回副本。这称为 NRVO(命名返回值优化)。下面两份代码可以证明。
    NRVO参考链接

    #include <iostream>
    using namespace std;
    
    class X {
    public:
        X() { cout << "Default Constructor" << endl; }
        X(const X&) { cout << "Copy Constructor" << endl; }
    };
    
    X f(X x) { return x; }
    
    X g() {
        X y;
        return y;
    }
    
    int main() {
        cout << "First create an object" << endl;
        X a;//a调用构造函数 输出Default Constructor
        cout << "Call f()" << endl;
        f(a);//传参时x=a调用拷贝构造函数 输出Copy Constructor   return时temp=x调用拷贝构造函数 输出Copy Constructor
    //    因为x是函数参数,所以有复制/移动 输出了2个Copy Constructor
        cout << "Call g()" << endl;
        g();//y调用构造函数 y的类型恰好是X 进行了优化 输出1次Default Constructor
    //    输出:
    //    First create an object
    //    Default Constructor
    //    Call f()
    //    Copy Constructor
    //    Copy Constructor
    //    Call g()
    //    Default Constructor
    
    }
    

    这里主要证明了NRVO中函数或 catch 子句参数不会被优化。

    in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

    #include <iostream>
    #include <cstring>
    using namespace std;
    class String{
    private:
        char *p;
    public:
        String(char *str){//这是自定义构造函数
            p=new char[strlen(str)+1];
            strcpy(p,str);
            cout << " constructor " << p << endl;
        }
        String(const String & c){//这是自定义拷贝构造函数
            p=new char[strlen(c.p)+1];
            strcpy(p,c.p);
            cout << "copy constructor " << p << endl;
        }
        String& operator = (const String &c)//赋值函数(赋值运算符重载) 传值 并没有被调用
        {
            cout << "assignment operator" << endl;
            p = c.p;
            return *this;
        }
        ~String(){
            delete[] p;
        }
    };
    String generate(){
        return String("test");
    //    return "test";和上面意义一样
    }
    String generate1(){
        String s("test");
        return s;
    }
    String generate2(String s){
        return s;
    }
    int main() {
        String tmp = generate();//调用1次构造函数  constructor test
        String S = tmp;//调用1次拷贝构造函数 copy constructor test
        String S2 = generate1();//调用1次构造函数  constructor test
        String S3 = generate2(S2);//s=S2 有一次拷贝构造  返回时tmp=s又有一次拷贝构造 输出2次copy constructor test
    //constructor test
    //copy constructor test
    //constructor test
    //copy constructor test
    //copy constructor test
    }
    

    为什么tmp=generate()并不会多执行一次拷贝构造?因为编译器先把tmp的指针传进generate,然后在返回的时候先把结果store进tmp的指针指向的内容,然后再调用拷贝构造函数。即构造函数时的对象指针就是用的tmp,不是额外新开的内存。

    移动构造函数

    在这里插入图片描述
    参考1 参考2

    若没有自定义拷贝构造、拷贝赋值、析构函数,编译器会合成默认的移动构造函数和移动赋值函数。

    • 拷贝构造有变,一般移动构造也会变
    • 析构函数管理额外申请的资源,编译器不负责,所以没有默认的函数

    触发时机: 如果临时对象即将消亡,并且它里面的资源是需要被再利用的,这个时候我们就可以触发移动构造。
    如下面的代码只有S=S2后,S3=S时使用了移动构造函数,因为S是即将消亡的临时对象,且资源可以被利用。

    #include <iostream>
    #include <cstring>
    using namespace std;
    class String{
    private:
        char *p;
    public:
        String(char *str){//这是自定义构造函数
            p=new char[strlen(str)+1];
            strcpy(p,str);
            cout << " constructor " << p << endl;
        }
        String(const String & c){//这是自定义拷贝构造函数
            p=new char[strlen(c.p)+1];
            strcpy(p,c.p);
            cout << "copy constructor " << p << endl;
        }
        String(String &&s):p(s.p){
            s.p = nullptr;
            cout << "move constructor " << p << endl;
        }
        String& operator = (const String &c)//赋值函数(赋值运算符重载) 传值 并没有被调用
        {
            cout << "assignment operator" << endl;
            p = c.p;
            return *this;
        }
        ~String(){
            delete[] p;
        }
    };
    String generate(){
        return String("test");
    }
    String generate1(){
        String s("test");
        return s;
    }
    String generate2(String s){
        return s;
    }
    int main() {
        String tmp = generate();//调用1次构造函数  constructor test
        String S = tmp;//调用1次拷贝构造函数 copy constructor test
        String S2 = generate1();//调用1次构造函数  constructor test
        String S3 = generate2(S2);//调用1次拷贝构造传参 再调用移动构造生成S
    //    触发时机: 如果临时对象即将消亡,并且它里面的资源是需要被再利用的,这个时候我们就可以触发移动构造。
    // constructor test
    //copy constructor test
    // constructor test
    //copy constructor test
    //move constructor test
    }
    

    另外,vector分配内存时也需要注意标记noexcept:

    为了避免这种潜在的问题,除非vector知道元素类型的移动构造函数不会抛出异常,否则在重新分配内存的过程中,它就必须使用拷贝构造函数而不是移动构造函数。如果希望在vector重新分配内存这类情况下对我们自定义类型的对象进行移动而不是拷贝,就必须显示的告诉标准库我们的移动构造函数可以安全使用。我们通过将移动构造函数(及移动赋值运算符)标记为noexcept来做到这一点。——《C++ primer》

    下面是有noexcept的情况:

    #include<iostream>
    #include<vector>
    #include<string>
    using namespace std;
    
    class Test
    {
    public:
        Test(const string& s = "hello world") :str(new string(s)) { cout << "constructor" << endl; };//构造函数
        Test(const Test& t);
        Test& operator=(const Test& t);
        Test(Test&& t) noexcept;
        Test& operator=(Test&& t) noexcept;
        ~Test();
    public:
        string * str;
    };
    
    Test::Test(const Test& t)//拷贝构造函数
    {
        str = new string(*(t.str));
        cout << "copy constructor" << endl;
    }
    Test& Test::operator=(const Test& t)//拷贝赋值运算符
    {
        cout << "assignment" << endl;
        return *this;
    }
    Test::Test(Test&& t)noexcept//移动构造函数
    {
        str = t.str;
        t.str = nullptr;
        cout << "move constructor" << endl;
    }
    Test& Test::operator=(Test&& t)noexcept//移动赋值运算符
    {
        cout << "move assignment" << endl;
        return *this;
    }
    Test::~Test()//析构函数
    {
        cout << "destructor" << endl;
    }
    
    int main()
    {
        vector<Test> vec(1);
        Test t("what");
        vec.push_back(std::move(t));//写move,会把左值显式变成右值引用,调移动构造函数move constructor what move constructor hello world
        vec.push_back(t);//t传参调用拷贝构造函数 copy constructor what move constructorhello world
        return 0;
    //输出:
    //constructor vector<Test> vec(1)  所以事先使用默认构造函数构造了一个Test对象
    //constructor Test t 使用默认构造函数构造了一个对象
    //中间两行见上
    //destructor   重新分配内存后,原来的内存将被销毁,所以输出一个“析构函数”
    //destructor   执行了return 0, 内存被释放,vec 和 t 都被析构,所以输出三个 “析构函数”(vec里面有2个对象)先销毁t
    //destructor 先销毁vec的第一个元素hello world
    //destructor 再销毁vec的第二个元素what
    }
    

    当不写noexcept时:

    • vec.push_back(t);//都是copy constructor
    • vec.push_back(std::move(t));//第一个是move 第二个是copy 因为move显式将左值变右值 调移动构造函数
    展开全文
  • 顾名思义,拷贝构造函数指的是将一个对象或者变量的值拷贝一份副本,这个副本和原来的就脱离关系,原来的对象或者指针指向的地址空间的内容改变了,不影响副本内存里的值,也就是说是深拷贝。 而移动构造函数就是把...
  • C++ 语言拷贝构造函数、拷贝赋值运算符和析构函数 每个类都定义了一个新类型和在此类型对象上可执行的操作。类可以定义构造函数,用来控制在创建此类型对象时做什么。一个类通过定义五种特殊的成员函数来控制这些...
  • C++拷贝构造函数移动构造函数
  • c++右值引用之转移构造函数文章中,我们介绍了移动构造函数三点注意问题 1、参数(右值)的符号必须是右值引用符号,即“&&”。 2、参数(右值)不可以是常量,因为我们需要修改右值。 3、 参数(右值)...
  • C++11移动构造函数详解

    千次阅读 2021-12-28 21:42:57
    C++在三种情况下会调用拷贝构造函数(可能有纰漏),第一种情况是函数形实结合时,第二种情况是函数返回时,函数栈区的对象会复制一份到函数的返回去,第三种情况是用一个对象初始化另一个对象时也会调用拷贝构造...
  • C++ 移动构造函数和拷贝构造函数

    千次阅读 多人点赞 2019-09-02 15:20:11
    我们用对象a初始化对象b,后对象a我们就不在使用了,但是对象a的空间还在呀... 拷贝构造函数中,对于指针,我们一定要采用深层复制,而移动构造函数中,对于指针,我们采用浅层复制。浅层复制之所以危险,是因为两...
  • 本文主要给大家介绍了关于C++移动构造函数及move语句的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。 首先看一个小例子: #include #include #include #include using ...
  • 初始化列表方式结合移动语义:调用移动拷贝构造函数 初始化时赋值方式结合移动语义:调用移动拷贝构造函数 初始化后赋值方式结合移动语义:调用赋值运算符重载函数; 2 示例代码 #include <iostream>...
  • 如下: string类的移动拷贝构造函数和赋值重载函数: list类的移动拷贝构造函数和一个赋值重载函数: 2.push_back和insert 在c++11标准库中,很多容器的push_back或者insert接口都至少会重载两个函数,其中一个函数...
  • 拷贝构造函数 拷贝构造函数就是用 同一类型的对象复制成员值来初始化对象(当出现类的 “=” 赋值时,就会调用拷贝构造函数) 简单来说,拷贝构造函数就是来复制对象的 如果类中没有定义拷贝构造函数,编译器会自行...
  • 最近项目的技术栈是C++,涉及到了C++中类的相关知识,其中对于类中的拷贝构造函数移动赋值运算符、移动构造函数和移动赋值运算符等函数有点混淆,在此记录下。 # 一、C++中的基本构造函数 C++是面向对象的语言,...
  • C++ 拷贝构造函数移动构造函数、拷贝赋值函数、移动赋值函数 这是个类的代码,我用这个类来讲诉 C++ 拷贝构造函数移动构造函数、拷贝赋值函数、移动赋值函数的使用。 例子: Speaker.h: #pragma once #ifndef _...
  • 构造函数,拷贝构造函数,移动构造函数,拷贝赋值运算符,移动赋值运算符应用场景 #include using namespace std; class ConstructTest{ public: ConstructTest(){ cout; dim_=0; base_= nullptr; }; ~ConstructTest...
  • 拷贝构造函数:用一个已存在的对象初始化一个不存在的对象 赋值构造函数:用一个“已存在”的对象初始化另一个“已存在”的对象 参考:https://blog.csdn.net/zcyzsy/article/details/52132936 移动构造函数:把...
  •  如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都没有默认值,则此构造函数是拷贝构造函数。(《C++Primer,第五版》) class Foo { public : Foo(); Foo(const Foo&); //拷贝构造函数 ...
  • (3)复制(拷贝构造函数 Student(Student&);//形参是本类对象的引用 (4)转换构造函数 Student(int r) ;//形参时其他类型变量,且只有一个形参 默认和初始化构造函数 默认构造函数和初始化构造函数在定义...
  • 上面两个类的拷贝构造函数都没有问题,B类的使用更加广泛,其中的原因还是和常量引用使用有关,常量引用可以接收引用和普通常量。 比如如下使用 template T makeT() { return T(); } makeT() //出现错误,return T...
  • 1、拷贝构造函数的基本概念 拷贝构造函数(copy constructor),先看一下拷贝构造函数的使用: #include <iostream> using namespace std; class testA { public: testA(int i):_i(i){}//初始化列表构造函数...
  • C++对于类都会自动生成“默认构造函数”和“默认拷贝构造函数”。 默认构造函数是不带参数的。 默认构造函数的作用是,给类中的变量分配内存空间。 对于类,编译器都会默认生成一个“不带参数的构造函数”,形式如下...
  • 移动构造函数与拷贝构造函数

    千次阅读 2021-03-07 11:15:14
    一、移动构造函数: 定义: 所谓移动语义,指的就是以移动而非深拷贝的方式初始化含有指针成员的类对象。简单的理解,移动语义指的就是将其他对象(通常是临时对象)拥有的内存资源“移为已用”。 优点: 提高执行...
  • 讲讲移动构造函数与拷贝构造函数的区别 :移动构造函数是c11的新特性,移动构造函数传入的参数是一个右值 用&&标出。一般来说左值可以通过使用std:move方法强制转换为右值。首先讲讲拷贝构造函数拷贝构造...
  • C++学习笔记3:拷贝构造移动构造

    千次阅读 2022-03-31 20:08:38
    一、拷贝构造函数 1、拷贝构造函数的语法: 拷贝构造函数名字(const 类名& ) {} 拷贝构造函数名字 -> 类名 形参列表:拷贝构造函数的第一个参数必须是本类对象的 const引用。 如果还需要其他的参数,...
  • C++移动构造函数

    2021-10-13 16:23:01
    C++ 11 标准之前,如果想用其它对象初始化一个同类的新对象,只能借助类中的拷贝构造函数拷贝构造函数的实现原理是为新对象复制一份和其它对象一模一样的数据。而当类中拥有指针类型的成员变量时,拷贝构造函数...
  • C++11移动构造函数详解 http://c.biancheng.net/view/7847.html C++拷贝和浅拷贝(深复制和浅复制)完全攻略 http://c.biancheng.net/view/2336.html
  • 主要介绍了C++中对构造函数和赋值运算符的复制和移动,是C++入门学习中的基础知识,需要的朋友可以参考下
  • 拷贝构造函数移动构造函数

    千次阅读 2018-06-11 15:08:54
    C++11之前,对象的拷贝控制由三个函数决定:拷贝构造函数(Copy Constructor)、拷贝赋值运算符(CopyAssignment operator)和析构函数(Destructor)。C++11之后,新增加了两个函数:移动构造函数(Move ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 31,923
精华内容 12,769
关键字:

c++移动拷贝构造函数

c++ 订阅