C++ primer 当vector中的push_back遇到移动构造函数会发生什么
2018-03-20 21:48
309 查看
首先仔细阅读 C++ primer 第五版 P474 Note下面的一段话
意思是说当我们在类中定义了移动构造函数的时候,假设这个移动构造函数是
noexcept的,类似对应
StrVec类的操作,
vector可能会重新分配内存,也就是说会将元素从旧空间移动到新内存中去。这个过程中就会发生
移动构造函数
注意
这里要注意一点,C++11规定的是移后源对象是一定要处于可析构的状态,意思是说移后源对象有可能执行析构函数,也有可能不执行析构函数,主要要看这个源对象在这个作用域生命周期是否结束吗,以下有例子可以说明。
默认初始化的vector是不分配内存空间的,当push_back发现vector空间不足以容纳新元素时,就会分配新的空间(通常是加倍),将数据移动到新空间时就会发生
移动构造函数,而当我们用
vs.reserve()预留足够的空间时,就不会发生移动构造函数了。
例子
使用C++ primer 中的String类,这里我使用
MyString,内容几乎一样。
1.代码如下:
int main() { MyString s1("FOne"), s2("Two"); vector<MyString> msvec; msvec.push_back(s1); msvec.push_back(s2); //msvec.push_back(std::move(s2)); //msvec.push_back(MyString("Three")); //msvec.push_back("Four"); //system("pause"); return 0; }
结果如下:
前三行容易理解,拷贝构造函数(push_back(s1))之后,发生了
移动构造函数和
析构函数,之后才又发生了一次拷贝构造函数。
原因就是开头的那一段话,由于我们这个类已经定义了移动构造函数,当push_back时候,会发生内存的重新分配,即将已经push_back进去的s1给移动到新内存,而这个移动后源对像是可析构的,并且应该销毁的,因为不再需要他了。故发生了
析构函数,之后再有
拷贝构造函数。
最后的四行
析构函数也不难理解了,将s1 s2 vector中的s1 s2给析构了。
2.代码如下
int main() { MyString s1("FOne"), s2("Two"); vector<MyString> msvec; msvec.push_back(s1); //msvec.push_back(s2); //msvec.push_back(std::move(s2)); //msvec.push_back(MyString("Three")); msvec.push_back("Four"); //system("pause"); return 0; }
结果如下:
和情况1大致相同,只是用
"Four"来构造了一个MyString实体。同样发生两次的
移动构造函数和
析构函数。
3.代码如下:
int main() { MyString s1("FOne"), s2("Two"); vector<MyString> msvec; msvec.push_back(s1); //msvec.push_back(s2); msvec.push_back(std::move(s2)); //msvec.push_back(MyString("Three")); //msvec.push_back("Four"); system("pause"); return 0; }
结果如下:
注意这次情况,我们push_back的是
std::move(s2),move函数将返回的是一个
右值,尽管s2是一个左值,那么此时发生
移动构造函数之后,移后源对象并没有直接发生析构,因为在这个作用域中s2的生命周期并未结束,而当return 0;
更要注意
结束的时候,发生了四次析构函数。这四次析构和第一种情况的四次析构并不一样。因为这个情况中的有一次析构,是析构移动后的s2,移动后的s2中并没有资源了,也就是说他的指针应该为
nullptr,
size应该为0。而对于第一种情况,四次析构全是有实体的,也就是说四次析构,析构的全是已经分配内存资源的实体。
通过调试,可以看到现在这个情况的四次析构:
第一次析构:
析构s1(vector中的),即
"FOne"。
第二次析构:
此时析构s2(vector中的),即
"Two"
第三次析构:
这次很特殊,
p为
nullptr,sz为0 ,也就是说此时我们释放的是已经移动后的s2,也就是移后源对像,因为他把资源交给了其他,故才有
p为
nullptr,sz为0这种情况。
第四次析构:
这次就是释放s1,很正常的
"FOne"。
对比第一种情况的四次析构,第一种情况的四次析构,都是销毁已经分配内存空间的实体,可以自己去调试。
总结:
1.C++11规定的是移后源对象是一定要处于可析构的状态,意思是说移后源对象有可能执行析构函数,也有可能不执行析构函数,视情况而定。2.当我们在类中定义了
移动构造函数,
push_back时
vector可能会重新分配内存,也就是说会将元素从旧空间移动到新内存中去。这个过程中就会发生
移动构造函数。
3.默认初始化的vector是不分配内存空间的,当push_back发现vector空间不足以容纳新元素时,就会分配新的空间(通常是加倍),将数据移动到新空间时就会发生
移动构造函数,而当我们用
vs.reserve()预留足够的空间时,就不会发生移动构造函数了。
相关文章推荐
- vector的push_back操作中关于构造函数析构函数的调用
- vector push_back 是否调用构造函数
- 一个空的vector执行pop_back操作会发生什么?
- 使用vector::push_back时,Release模式发生错误void __cdecl _CRT_DEBUGGER_HOOK(int _Reserved)
- 关于vector在堆上还是在栈上的思考与vector.push_back()究竟放入的是什么
- STL:vector中push_back实现斐波纳契数列计算
- C++13.1.2合成复制构造函数----定义复制对象时会发生什么
- 请教一个vector的push_back问题
- c++ vector中resize、reserve、push_back和capacity
- vector push_back可能出错
- 关于vector push_back()与其他方式读取数据的效率对比
- vector的push_back
- 当 FreeBSD 遇到 Ubuntu 会发生什么?ubuntuBSD 项目发布安装镜像
- vector中的push_back函数的意思是什么
- 对于 std::vector<T> , 当T没有赋值运算符函数的时候,如何调用vector push_back?
- STL源码分析之vector(二)—核心函数 push_back及insert_aux
- vector::push_back() demo
- C++ vector::push_back 用法剖析
- C++ vector 和push_back 详解