C++11标准之后的移动构造函数和复制构造函数探究

如下一个类的定义,其定义了类的复制构造函数,和移动构造函数

class B
{
public:
     B() :data(0)    //默认构造函数  
    {
        cout << "Default constructor is called." << endl;
    }
    B(int i) :data(i) //带参数的构造函数  
    {
        cout << "Constructor is called." << data << endl;
    }
    B(const B &b)   // 复制(拷贝)构造函数  
    {
        data = b.data; 
        cout << "Copy Constructor is called." << data << endl;
    }
    B(B&& b)      // 移动构造函数,严格意义上移动构造函数的作用是,this去接管b的资源,同时b的资源被销毁
    {
        this->data = b.data;
        cout << "Move Constructor is called." <<data<< endl;
    }
    B& operator = (const B &b) //赋值运算符的重载  
    {
        this->data = b.data;
        cout << "The operator \"= \" is called." << data << endl;
        return *this;
    }
    ~B() //析构函数  
    {
        cout << "Destructor is called. " << data <<" "<<&data<< endl;
    }
private:
    int data;
};
B fun(B c)
{
    return c;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

注意到在cppreference里面有如下一段话

When used as a function argument and when two overloads of the function are available, one taking rvalue reference parameter and the other taking lvalue reference to const parameter, an rvalue binds to the rvalue reference overload (thus, if both copy and move constructors are available, an rvalue argument invokes the move constructor, and likewise with copy and move assignment operators).
作为函数参数[argument],如果有两个重载函数可用[avaliable],其中一个把右值引用作为参数[parameter],另一个把常左值引用作为参数,那么右值会绑定[bind to]那个把右值引用作为参数的重载函数。(因此,在拷贝构造函数和移动构造函数都可用[available]的情况下,右值参数会调用[invoke]移动构造函数,拷贝赋值符号和移动赋值符号与之类似。)

所以在定义了移动构造函数的情况下,在实参(argument)是一个右值(rvalue,包括xvalue和prvalue)的情况下会调用移动构造函数,而不是调用复制构造函数
所以运行。所以如下代码的运行结果为:

B a0(0);
B a1 = fun(a0);
 
 
  • 1
  • 2

输出结果:

Constructor is called.0 //a0的构造函数
Copy Constructor is called.0 //a0做为参数传入fun函数,此时a0是一个左值,所以会调用复制构造函数
Move Constructor is called. //函数返回值传出时,因为调用的是一个右值,所以调用了移动构造函数
Destructor is called. 0 00FFFB30 //先析构函数参数里的那个形参c
Destructor is called. 0 00FFFC1C //再析构a1
Destructor is called. 0 00FFFC28 //最后析构a0

同时还应该注意另外一个问题,就是移动构造函数的缺省定义的问题

If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:

  • there are no user-declared copy constructors;
  • there are no user-declared copy assignment operators;
  • there are no user-declared move assignment operators;
  • there are no user-declared destructors;

就是当用户显示的定义复制构造函数或重载赋值运算符时,就不会有隐式的移动构造函数了,这点一定要注意。所以将上面那行代码删去移动构造函数那一段,则代码运行结果就为:

Constructor is called.0
Copy Constructor is called.0
Copy Constructor is called.0 //即函数返回值来构造a1时,因为没有移动构造函数了,所以此时调用的是复制构造函数
Destructor is called. 0 00CFFC70
Destructor is called. 0 00CFFD5C
Destructor is called. 0 00CFFD68

另外也注意一下析构的顺序,就是Copy或者Move完了之后,在析构函数里的东西,而析构的时候,是从下往上析构的,即后定义的先析构,就是因为栈空间的问题吧。所以函数里定义的析构完了之后,才开始析构函数的形参。

最后一个需要注意的问题如果把上述的移动构造函数显示写出来,然后给delete掉之后

B(B&& b)  = delete;
 
 
  • 1

因为有显示的移动构造函数被定义出来,此时这个程序会调用这个移动构造函数,但是因为其被删除了,程序就会显示会调用已经被删除的程序,而报错。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值