c++中vector在push_back时调用移动构造函数

c++构造函数的调用

c++11中构造函数包括:

  • 默认构造函数
  • 拷贝构造函数
  • 移动构造函数
  • 拷贝赋值函数
  • 移动赋值函数

那么请思考下面的一个案例中其调用的顺序是怎样的:

class A {
public:
    A() {
        printf("A()--默认构造\n");
    }
    ~A() {
        printf("~A()--析构函数\n");
    }
    A(const A &a) {
        printf("A(const A& a)--复制构造\n");
    }
    A(A &&a) {
        printf("A(A&& a)--移动构造\n");
    }
    A &operator=(const A &a) {
        printf("operator=(const A& a)--赋值构造\n");
        return *this;
    }
    A &operator=(A &&a) {
        printf("operator=(A&& a)--移动赋值构造\n");
        return *this;
    }
};

int main() {
    std::vector<A> vec;
    vec.reserve(2);
    for (int i = 0; i < 4; ++i) {
        cout<<i<<endl;
        vec.push_back(A());
    }
    cout<<"------"<<endl;
    vec.resize(8);
    cout<<"-------"<<endl;
    return 0;
}

输出为:

0
A()--默认构造
A(A&& a)--移动构造
~A()--析构函数
1
A()--默认构造
A(A&& a)--移动构造
~A()--析构函数
2
A()--默认构造
A(A&& a)--移动构造
A(const A& a)--复制构造
A(const A& a)--复制构造
~A()--析构函数
~A()--析构函数
~A()--析构函数
3
A()--默认构造
A(A&& a)--移动构造
~A()--析构函数
------
A()--默认构造
A()--默认构造
A()--默认构造
A()--默认构造
A(const A& a)--复制构造
A(const A& a)--复制构造
A(const A& a)--复制构造
A(const A& a)--复制构造
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数
-------
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数

需要重点关注的地方(为什么使用复制构造而不用移动构造呢?):
在这里插入图片描述
当重新分配vector的内存时 vector将元素从旧空间移动到新内存中,虽然移动操作通常不会抛出异常,但是抛出异常也是允许的;因为A对象的移动构造没有标记为noexcept,为了避免移动失败的问题,使用了复制构造;
如果希望vector 重新分配内存这类情况下,对我们自定义类型的对象进行移动,而不是拷贝, 就必须显示的告诉标准库,我们的移动构造函数可以安全使用,那下面让我们将移动构造函数标记为noexcept

class A {
public:
    A() {
        printf("A()--默认构造\n");
    }
    ~A() {
        printf("~A()--析构函数\n");
    }
    A(const A &a) {
        printf("A(const A& a)--复制构造\n");
    }
    A(A &&a) noexcept{
        printf("A(A&& a)--移动构造\n");
    }
    A &operator=(const A &a) {
        printf("operator=(const A& a)--赋值构造\n");
        return *this;
    }
    A &operator=(A &&a) {
        printf("operator=(A&& a)--移动赋值构造\n");
        return *this;
    }
};

int main() {
    std::vector<A> vec;
    vec.reserve(2);
    for (int i = 0; i < 4; ++i) {
        cout<<i<<endl;
        vec.push_back(A());
    }
    cout<<"------"<<endl;
    vec.resize(8);
    cout<<"-------"<<endl;
    return 0;
}

输出为:

0
A()--默认构造
A(A&& a)--移动构造
~A()--析构函数
1
A()--默认构造
A(A&& a)--移动构造
~A()--析构函数
2
A()--默认构造
A(A&& a)--移动构造
A(A&& a)--移动构造
A(A&& a)--移动构造
~A()--析构函数
~A()--析构函数
~A()--析构函数
3
A()--默认构造
A(A&& a)--移动构造
~A()--析构函数
------
A()--默认构造
A()--默认构造
A()--默认构造
A()--默认构造
A(A&& a)--移动构造
A(A&& a)--移动构造
A(A&& a)--移动构造
A(A&& a)--移动构造
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数
-------
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数
~A()--析构函数

可以看到这次在vector重新分配内存后,是对对象进行了移动,而不是拷贝;

移动赋值运算符和移动构造时相同的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值