复盘——vector 的 push_back() 和 emplace_back()——函数返回值

又被拷打了捏,问起来还是不会细节…

vector 的 push_back() 和 emplace_back()

我们来看一些代码:

在这里插入图片描述

vec是vector

1.传递对象实例
在这里插入图片描述

2.传递临时对象
在这里插入图片描述

3.直接传递数据成员(主要要按顺序)
在这里插入图片描述
所以总结:
当%_back()的是 类对象实例 或者 临时对象 的时候,两者没有区别;
直接传递数据成员 的时候就不一样了:
push_back():先调用第二种构造,构造出临时变量,接着调用 移动构造/拷贝构造 函数,在vector的内存上面构造。
Emplace_back():直接调用第二种构造在vector的内存上面构造。

那么具体是怎么构造的呢?为什么会这样?

看源码:(说实话,还没没看懂是怎么构造的…)

关键就是 Emplace_back()用了 完美转发 + 可变模板参数 的技术;

Push_back() 底层用的就是emplace_back(),但是它只能接受对象引用以及右值引用,而不能直接接受 成员数据 作为参数:
在这里插入图片描述
因此push_back()无法接受 成员数据 作为参数;

而对于 emplace_back() 就不一样了,emplace_back()用了一个 可变模板参数 + 完美转发的技术:
在这里插入图片描述然后通过不断的 forward完美转发,分为下面的几种情况:
1. 传进来的是左值: 那么args就是一个左值,一直转发,最后调用拷贝构造函数,所以push_back(),emplace_back()是一样的;
2. 传进来的是右值: 那么args就是一个右值,一直转发,最后调用移动构造函数/拷贝构造函数,所以两者还是一样;
3. 传进来的是类的成员数据作为参数: 那么args就是一堆参数了,可能不只是一个了,那么一直转发,最终将调用我们实现的函数
在这里插入图片描述
在vector末尾直接构造。

函数返回值

接着来看个有意思的现象:(构造函数们还是上面的构造函数)


在这里插入图片描述
在这里插入图片描述
非常的合理,函数返回值是右值,调用移动构造函数;


在这里插入图片描述

在这里插入图片描述
段错误了…
但是我们把构造函数里面注释了,就不会段错误了…
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
非常合理,函数返回引用,引用是左值,所以调用拷贝构造函数;


那么问题来了,同样是返回引用,为什么第二个会段错误呢?

本质就是对函数返回值和内存管理没有正确的认识…

首先我们要知道一个知识点:
对于 堆、栈、全局区 中的变量的生命周期是不同的!

对于栈中的变量,也就是我们直接定义的变量(不通过malloc,new;非静态),其生命周期是在它的作用域里面,离开了作用域则自动销毁了!

对于堆中的变量,也就是我们malloc,new的变量,即使其离开了作用域,但是生命周期仍存在,所以需要我们手动delete掉;

对于全局区中的变量,它的作用域的整个程序,所以程序结束后才销毁;

回到上面的问题:
由于 fun1 返回的局部变量的值,即使是局部变量(在栈上,离开函数后销毁),但是返回的是值,也就是会产生一个临时变量,返回的是临时变量,通过临时变量构造,没有问题。

由于fun2返回的是局部变量的引用,而局部变量在栈上,离开函数后销毁,并且并且由于返回值是引用,所以并不会产生临时变量,该引用是函数中a的引用,而函数结束后a销毁了,引用就变成了未定的,所以在拷贝构造函数中使用a._x的时候就出错了,因为a的内存空间已经被销毁了;这也是为什么注释掉后就不会了;

再看fun3,同样返回引用,但是注意到函数中的变量是new出来的,在堆上(离开函数后并不会销毁),因此返回的引用是有效的!因此不会报错;

有意思的是,返回字符串也没问题:
在这里插入图片描述
因为首先返回的是指针,且不是new出来的,但是hello是常量,放在常量区(属于全局区),所以函数结束后不会被销毁。(同理static也是一样的)

在这里插入图片描述
最后一句话的意思是:函数 传出参数 的意思。

参考文章:
C++:vector的push_back()与emplace_back()

C++vector等容器使用push_back和emplace_back的区别

vector中emplace_back和push_back详解,源码解读

C++中push_back和emplace_back的区别

泛化之美–C++11可变模版参数的妙用

C++函数返回值

我是一个找实习的鼠鼠,今天又是 0 offer 的一天,加油吧!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值