关于c++中vector的push_back、拷贝构造copy constructor和移动构造move constructor
问题来自C++ Primer的第十三章练习题的13.48.是这样说的:
定义一个vector<String>并在其上多次调用push_back运行你的程序,并观察String被拷贝了多少次。
其中String是在习题中自己写的一个类似标准库string的类。(第一次看,自己写的String类确实有点挫,于是直接用了github上找到的CppPrimer答案中的String类。
//String.hclass String {
public:String() : String("") {}String(const char*);String(const String&);String& operator=(const String&);String(String&&);String& operator=(String&&);~String();const char* c_str() const { return elements; }size_t size() const { return end - elements; }size_t length() const { return end - elements - 1; }private:std::pair<char*, char*> alloc_n_copy(const char*, const char*);void range_initializer(const char*, const char*);void free();private:char* elements;char* end;std::allocator<char> alloc;
};std::pair<char*, char*> String::alloc_n_copy(const char* b, const char* e)
{auto str = alloc.allocate(e - b);return{ str, std::uninitialized_copy(b, e, str) };
}
void String::range_initializer(const char* first, const char* last)
{auto newstr = alloc_n_copy(first, last);elements = newstr.first;end = newstr.second;
}
String::String(const char* s)
{char* sl = const_cast<char*>(s);while (*sl) ++sl;range_initializer(s, ++sl);
}
String::String(const String& rhs)
{range_initializer(rhs.elements, rhs.end);std::cout << "copy constructor" << std::endl;
}String& String::operator=(const String& rhs)
{auto newstr = alloc_n_copy(rhs.elements, rhs.end);free();elements = newstr.first;end = newstr.second;std::cout << "copy-assignment operator" << std::endl;return *this;
}
String::String(String &&s) :elements(s.elements), end(s.end)
{s.elements = s.end = nullptr;cout << "move constructor" << endl;
}
String& String::operator=(String &&s)
{if (this != &s){free();elements = s.elements;end = s.end;s.elements = s.end = nullptr;}cout << "move-assignment operator" << endl;return *this;
}
void String::free()
{if (elements) {std::for_each(elements, end, [this](char& c) { alloc.destroy(&c); });alloc.deallocate(elements, end - elements);}
}
String::~String()
{free();
}
String类中定义了拷贝构造和移动构造函数,并且在调用的时候打印提示信息。
一开始遇到的问题是(那时候书上还没有讲到移动构造函数,相当于把上面头文件中的移动构造给注释掉,只有拷贝构造),我随便写了测试:
void printInfo(vector<String> &v)
{cout << "size:" << v.size() << " " << "capacity:" << v.capacity() << endl;
}
int main()
{String s0("hello");vector<String> vec;printInfo(vec);vec.push_back(s0);printInfo(vec);vec.push_back(s0);printInfo(vec);vec.push_back(s0);printInfo(vec);vec.push_back(s0);printInfo(vec);system("pause");return 0;
}
结果是这样的:
由于push_back是调用的copy constructor,可以看到每一次push_back除了调用一次copy constructor外还要额外调用多次。当时我没想到是因为vector中的预留空间不足,需要额外分配空间(其实就是这个原因)。
而以上是没有移动构造的时候。下面加入了移动构造后,结果变成了:
这次更加直观了,可以看到,每次push_back在copy之前还要首先将已有的元素通过调用move constructor来移动,留出空间,然后再copy添加元素。之前之所以调用的全是copy constructor是因为没有定义move constructor,而此时编译器也不会自动合成(primer后面有说),这时候只能调用拷贝构造,效率就降低了。
那么可以预料,如果在测试之前首先调用vector的reserve方法预留出空间,那么就不需要一次次调用move constructor了。
结果如下:
这次在push_back之前加了一句
vec.reserve(4);
于是不再需要分配空间。
结论:vector添加元素在空间不够的时候需要重新分配,此时对于原来已有的元素会调用对象类的move constructor,而如果对象类没有定义移动构造,则会 使用copy constructor。所以给类添加移动构造函数可以在很多时候提高效率,因为没有它只能用拷贝构造来替代,而编译器又不会自动合成一个。
Cpp Primer是本好书,就是第一次啃有点慢= =。
关于c++中vector的push_back、拷贝构造copy constructor和移动构造move constructor相关推荐
- vector的push_back拷贝构造和空间占用分析
本文同步自:http://zohead.com/archives/vector-push-back-space-copy/ 这两天在实际程序中使用 STL 的 vector push_back 类对象 ...
- C++ vector向量pushback拷贝构造需要注意的几点
vector 在 push_back 时的调用类对象的拷贝构造函数和析构函数有点特别,简单做下分析. 程序代码: #include <iostream> #include <vect ...
- C++ 中emplace_back和push_back差异
前言 最近看rocskdb源码,发现了大量的设计模式和C++高级特性,特此补充一下,巩固基础. 问题描述 其中关于动态数组的元素添加,代码中基本将push_back抛弃掉了,全部替换为emplace_ ...
- [转贴]从零开始学C++之STL(二):实现一个简单容器模板类Vec(模仿VC6.0 中 vector 的实现、vector 的容量capacity 增长问题)...
首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下: C++ Code 1 2 template < class _Ty, cla ...
- C++:vector的push_back()与emplace_back()
在STL中,向vector容器添加元素的函数有2个:push_back().emplace_back() 1.push_back() 在vector容器尾部添加一个元素,用法为: arr.push_b ...
- opencv中vector类的介绍
1.c++中vector的用法详解 vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当不知道数组的个数的时候 可以使用vector<int>a; ...
- c++中vector的用法详解
c++中vector的用法详解 vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间 ...
- C++中vector容器为什么扩容时按照2倍或者1.5倍进行扩容
扩容机制 首先在VS2013底下,vector的扩容操作是每次扩容*1.5:在GCC环境下是2倍. GCC下的扩容方式是以二倍形式扩容. VS2013下是以1.5倍进行扩容 所以可能会有疑问: 问题一 ...
- STL中Vector的内存分配机制
一些好的公司校园招聘过程中(包括笔试.面试环节),经常会涉及到STL中vector的使用(主要是笔试)及其性能(面试)的分析.今天看了下相关文章,也写了几个小的测试程序跑了跑.算是总结下,希望对需要的 ...
最新文章
- MYSQL二级表的管理_MySQL分区表的管理~2
- Android开发笔记——常见BUG类型之内存泄露与线程安全
- 1滴血,2小时,验13种癌症,精度99%!日本东芝新技术引热议
- Maven 概要介绍
- 导入依赖和加上注释后,lombok gettersetter识别不到
- Servlet到底是个什么东西???【【博采众长】】
- 解读STM32标准库的程序架构 - 以GPIO操作为例
- 21 RadioGroup ListFragment
- 项目管理工具strber
- LOB字段存放在指定表空间 清理CLOB字段及压缩CLOB空间
- 分数加减乘除混合运算带答案_分数分数加减乘除混合运算练习题及答案_0.doc
- javascript promise
- OSI参考模型与排错经验谈
- 多步骤查询的解决方案
- ISIS出现(Project2.sct(7): error: L6236E: No section matches selector - no section to be FIRST/LAST.)异常
- 双屏幕切换成单屏,软件不显示的问题与解决方法(总结全网)
- 2011热门论坛排行top100
- 几款好看的css表格
- 【独立游戏】如何完成一款游戏? | 独立游戏制作
- 搜狗浏览器显示服务器dns,为你设置win10系统下搜狗浏览器无法解析服务器的dns地址的处理对策...