代码要点
- placement new:原地构造对象,避免内存频繁地申请和释放
- 手动析构 + operator delete:和placement new配套使用,析构对象不一定要释放内存
- 三个指针成员:当然也可以一个指针 + size + capacity,但gcc中用的是三个指针
- ~MyVector():不可以写成~MyVector() { delete(_start); },否则只有 _start指向的元素会被析构
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
| #include <iostream> #include <algorithm> #include <vector> #include <chrono>
template<typename T> class MyVector { private: T* _start; T* _finish; T* _end_of_range;
void reallocate() { size_t oldCapacity = capacity(); size_t newCapacity = oldCapacity ? 2 * oldCapacity : 1;
T* newStart = static_cast<T*>(operator new(newCapacity * sizeof(T))); if (!newStart) { throw std::bad_alloc(); } size_t oldSize = size(); for (T* p = _start; p != _finish; p++) { new (newStart + (p - _start)) T(*p); }
for (T* p = _start; p != _finish; ++p) { p->~T(); }
operator delete(_start);
_start = newStart; _finish = _start + oldSize; _end_of_range = _start + newCapacity; }
void shiftRight(T* first, T* last) { for (T* p = last; p > first; --p) { new (p) T(*(p - 1)); (p - 1)->~T(); } }
void shiftLeft(T* first, T* last) { for (T* p = first; p < last - 1; ++p) { p->~T(); new (p) T(*(p + 1)); } (last - 1)->~T(); }
public: MyVector() : _start(nullptr), _finish(nullptr), _end_of_range(nullptr) {}
explicit MyVector(size_t n) { _start = static_cast<T*>(operator new(n * sizeof(T))); _finish = _start + n; _end_of_range = _start + n;
for (T* p = _start; p != _finish; ++p) { new (p) T(); } }
~MyVector() { for (T* p = _start; p != _finish; ++p) { p->~T(); } operator delete(_start); }
size_t size() const { return _finish - _start; }
size_t capacity() const { return _end_of_range - _start; }
bool empty() const { return _start == _finish; }
T& operator[](size_t index) { return *(_start + index); }
const T& operator[](size_t index) const { return *(_start + index); }
void push_back(const T& value) { if (_finish == _end_of_range) { reallocate(); }
new (_finish) T(value); ++_finish; }
void pop_back() { if (!empty()) { _finish--; _finish->~T(); } }
void insert(size_t pos, const T& value) { if (pos > size()) { throw std::out_of_range("Insert position out of range"); } if (_finish == _end_of_range) { reallocate(); } T* insertPos = _start + pos; shiftRight(insertPos, _finish); new (insertPos) T(value); ++_finish; }
void erase(size_t pos) { if (pos >= size()) { throw std::out_of_range("Erase position out of range"); } T* erasePos = _start + pos; erasePos->~T(); shiftLeft(erasePos, _finish); --_finish; }
T& front() { if (empty()) { throw std::out_of_range("Vector is empty"); } return *_start; }
T& back() { if (empty()) { throw std::out_of_range("Vector is empty"); } return *(_finish - 1); }
void clear() { for (T* p = _start; p != _finish; ++p) { p->~T(); } _finish = _start; } };
template<typename VectorType> void testInsertion(size_t numElements) { VectorType vec; auto start = std::chrono::high_resolution_clock::now(); for (size_t i = 0; i < numElements; ++i) { vec.push_back(i); } auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); std::cout << "插入 " << numElements << " 个元素耗时: " << duration << " 毫秒" << std::endl; }
template<typename VectorType> void testAccess(size_t numElements) { VectorType vec; for (size_t i = 0; i < numElements; ++i) { vec.push_back(i); } auto start = std::chrono::high_resolution_clock::now(); for (size_t i = 0; i < numElements; ++i) { volatile auto value = vec[i]; } auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); std::cout << "访问 " << numElements << " 个元素耗时: " << duration << " 毫秒" << std::endl; }
void functionTest() { MyVector<int> vec(3);
vec.push_back(10); vec.push_back(20); vec.push_back(30);
std::cout << "第一个元素: " << vec[0] << std::endl; std::cout << "第二个元素: " << vec[1] << std::endl;
vec[1] = 25; std::cout << "修改后的第二个元素: " << vec[1] << std::endl;
vec.pop_back(); std::cout << "删除最后一个元素后,MyVector 的大小: " << vec.size() << std::endl;
vec.insert(1, 40); std::cout << "插入元素后,第二个元素: " << vec[1] << std::endl;
vec.erase(1); std::cout << "删除元素后,第二个元素: " << vec[1] << std::endl;
std::cout << "首元素: " << vec.front() << std::endl; std::cout << "尾元素: " << vec.back() << std::endl;
vec.clear(); std::cout << "清除元素后,MyVector 的大小: " << vec.size() << std::endl; }
int main() {
const size_t numElements = 10000000;
std::cout << "MyVector 测试:" << std::endl; testInsertion<MyVector<int>>(numElements); testAccess<MyVector<int>>(numElements);
std::cout << "\nstd::vector 测试:" << std::endl; testInsertion<std::vector<int>>(numElements); testAccess<std::vector<int>>(numElements);
return 0; }
|
测试结果
gcc下:

惊人地发现我们随便手写的vector比std::vector更快
一些猜测的可能解释如下:
- std::vector有更严格的安全和异常检查,运行时开销更大
- std::vector不是直接使用的placement new,而是用的allocator模板类,在其中使用的placement new;而allocator的复杂设计中可能会带来一些运行时开销