文章目录
前言
对于自己尝试写的一些模仿标准库等操作。永远不要觉得自己实现的有多nb,在各大编译器的标准库面前就是个弟弟。
因此别再觉得自己数据结构课上写的那些基础线性表操作有多熟料,只能说人外有人,山外有山。
对于实现一个vector的基本考虑
- 数据类型的声明
- 构造 constructor
- 析构 destructor
- 拷贝 移动 copy move
- 迭代器 iterators
- 存取器 accessor
- 容量 capacity
- 修改器 modifier
- 尾部追加删除 do_back
- 运算符重载
- 等等等等
Code
本文参考 LH_Mouse 的简单vector的实现,作为笔记和交作业。
LH_Mouse 的基础版本
手写一个 std::vector 可以有多复杂?_哔哩哔哩_bilibili
这只是在短时间内能考虑到的简单版本~
#include <stddef.h>
#include <iostream>
#include <string>
namespace my {
template <class ValueT>
class vector {
public:
using value_type = ValueT;
using reference = ValueT&;
using const_reference = const ValueT&;
using iterator = ValueT*;
using const_iterator = const ValueT*;
using size_type = ::size_t;
// 迭代器相减
using difference_type = ::ptrdiff_t;
private:
ValueT* m_data;
::size_t m_size;
::size_t m_capacity;
public:
// 默认无参构造
constexpr vector() noexcept : m_data(), m_size(), m_capacity() {
}
// 内存是vector自己管理的
// 只想销毁对象
~vector() {
this->clear();
::operator delete(this->m_data);
}
// 拷贝构造
vector(const vector& rhs) {
// 注意 operator new 会抛出异常
this->m_data = static_cast<ValueT*>(
::operator new(rhs.m_capacity * sizeof(ValueT)));
this->m_size = 0;
this->m_capacity = rhs.m_capacity;
try {
for (::size_t k = 0; k < rhs->m_size; k += 1) {
// placement new
// new时考虑异常
::new (&this->m_data[k]) ValueT(rhs.m_data[k]);
this->m_size += 1;
}
} catch (...) {
for (::size_t k = 0; k < this->m_size; k += 1) {
this->m_data[k].~ValueT();
}
::operator delete(this->m_data);
// 将异常重新抛出
throw;
}
}
// 移动构造
vector(vector&& rhs) {
this->m_data = rhs.m_data;
this->m_size = rhs.m_size;
this->m_capacity = rhs.m_capacity;
rhs.m_data = nullptr;
rhs.m_size = 0;
rhs.m_capacity = 0;
}
vector& operator=(const vector& rhs) {
return *this;
}
vector& operator=(vector&& rhs) {
return *this;
}
public: // 涉及到指针的,需要考虑const版本
// iterators
iterator begin() noexcept {
return this->m_data;
}
const_iterator begin() const noexcept {
return this->m_data;
}
iterator end() {
return this->m_data + this->m_size;
}
const_iterator end() const {
return this->m_data + this->m_size;
}
// accessor
value_type* data() noexcept {
return this->data;
}
const value_type* data() const noexcept {
return this->m_data;
}
size_type size() const noexcept {
return this->m_size;
}
size_type capacity() const noexcept {
return this->m_capacity;
}
bool empty() const noexcept {
return this->m_size == 0;
}
// modifier
void clear() noexcept {
for (::size_t k = 0; k < this->m_size; k += 1) {
this->m_data[k].~ValueT();
}
this->m_size = 0;
}
void pop_back() noexcept {
// 保证size>0
assert(!this->empty());
::size_t k = this->m_size - 1;
this->m_data[k].~ValueT();
this->m_size += -1;
}
void push_back(const ValueT& value) {
this->emplace_back(value);
}
void push_back(ValueT&& value) {
this->emplace_back(::std::move(value));
}
template <typename... Args>
reference emplace_back(Args&&... args) {
if (this->m_size < this->m_capacity) {
// `data` can not be null
::size_t k = this->m_size;
::new (&this->m_data[k]) ValueT(::std::forward<Args>(args)...);
this->m_size += 1;
return this->m_data[k];
}
// 此时 size == capacity
// 扩容1.5倍
::size_t new_capacity = this->m_size + 1;
new_capacity |= this->m_size / 2;
::size_t new_size = 0;
auto new_data =
static_cast<ValueT*>(::operator new(new_capacity * sizeof(ValueT)));
try {
for (::size_t k = 0; k < this->m_size; k += 1) {
// placement new
// new时考虑异常
::new (&new_data[k]) ValueT(::std::move(this->m_data[k]));
new_size += 1;
}
::new (&new_data[new_size]) ValueT(::std::forward<Args>(args)...);
new_size += 1;
} catch (...) {
for (::size_t k = 0; k < new_size; k += 1) {
new_data[k].~ValueT();
}
::operator delete(new_data);
// 将异常重新抛出
throw;
}
// 将原数据析构
this->clear();
::operator delete(this->m_data);
this->m_data = new_data;
this->m_size = new_size;
this->m_capacity = new_capacity;
return new_data[new_size];
}
};
} // namespace my
int main() {
::my::vector<::std::string> vec;
vec.push_back("hello");
vec.emplace_back();
vec.emplace_back("hello", 4);
// 标准不禁止
// vec.emplace_back(vec[0]);
for (const auto& str : vec) {
::std::cout << str << ::std::endl;
}
return 0;
}
简单改良
真的,楼主感觉喵喵写已经非常优良和精简了。个人也只是做了简单的补充和注释。
比如补了一下赋值操作,简单封装了析构的功能函数等。
注意这里还是有很多情况没有考虑,以个人能力非要考虑的话也只能写出效率极低,冗余度高的丑陋代码
- 如果考虑以迭代器为参数构造
- 只能访问一次的迭代器该如何处理
- 扩容时候插入的元素为原序列本身的元素
- 扩容时移动到新空间错误
- 部分new操作没考虑异常
- 等等等等
#include <stddef.h>
#include <iostream>
#include <string>
namespace my {
template <class ValueT>
class vector {
public:
using value_type = ValueT;
using reference = ValueT&;
using const_reference = const ValueT&;
using iterator = ValueT*;
using const_iterator = const ValueT*;
using size_type = ::size_t;
// 迭代器相减
using difference_type = ::ptrdiff_t;
private:
ValueT* m_data;
::size_t m_size;
::size_t m_capacity;
public:
// 默认无参构造
constexpr vector() noexcept : m_data(), m_size(), m_capacity() {
}
// 内存是vector自己管理的
// 只想销毁对象
~vector() {
this->destruct_this();
}
// 拷贝构造
vector(const vector& rhs) {
// 注意 operator new 会抛出异常
this->m_data = static_cast<ValueT*>(
::operator new(rhs.m_capacity * sizeof(ValueT)));
this->m_size = 0;
this->m_capacity = rhs.m_capacity;
try {
for (::size_t k = 0; k < rhs->m_size; k += 1) {
// new时考虑异常
::new (&this->m_data[k]) ValueT(rhs.m_data[k]);
this->m_size += 1;
}
} catch (...) {
destruct_this();
throw;
}
}
// 移动构造
vector(vector&& rhs) {
this->m_data = rhs.m_data;
this->m_size = rhs.m_size;
this->m_capacity = rhs.m_capacity;
rhs.m_data = nullptr;
rhs.m_size = 0;
rhs.m_capacity = 0;
}
// 偷懒的写法
vector& operator=(const vector& rhs) {
auto tmp = rhs;
using ::std::swap;
swap(tmp, *this);
return *this;
}
vector& operator=(vector&& rhs) {
auto tmp = ::std::move(rhs);
using ::std::swap;
swap(tmp, *this);
return *this;
}
public: // 涉及到指针的,需要考虑const版本
// iterators
iterator begin() noexcept {
return this->m_data;
}
const_iterator begin() const noexcept {
return this->m_data;
}
iterator end() {
return this->m_data + this->m_size;
}
const_iterator end() const {
return this->m_data + this->m_size;
}
// accessor
value_type* data() noexcept {
return this->data;
}
const value_type* data() const noexcept {
return this->m_data;
}
size_type size() const noexcept {
return this->m_size;
}
size_type capacity() const noexcept {
return this->m_capacity;
}
bool empty() const noexcept {
return this->m_size == 0;
}
// modifier
void clear() noexcept {
destruct_len(this->m_data, this->m_size);
this->m_size = 0;
}
void pop_back() noexcept {
// 保证size>0
assert(!this->empty());
::size_t k = this->m_size - 1;
this->m_data[k].~ValueT();
this->m_size += -1;
}
// 调用 emplace_back
void push_back(const ValueT& value) {
this->emplace_back(value);
}
void push_back(ValueT&& value) {
this->emplace_back(::std::move(value));
}
// 注意要使用完美转发
template <typename... Args>
reference emplace_back(Args&&... args) {
if (this->m_size < this->m_capacity) {
::size_t k = this->m_size;
::new (&this->m_data[k]) ValueT(::std::forward<Args>(args)...);
this->m_size += 1;
return this->m_data[k];
}
// 此时 size == capacity
// 扩容1.5倍
::size_t new_capacity = this->m_size + 1;
new_capacity += this->m_size / 2;
::size_t new_size = 0;
auto new_data =
static_cast<ValueT*>(::operator new(new_capacity * sizeof(ValueT)));
try {
for (::size_t k = 0; k < this->m_size; k += 1) {
// 并不是所有情况下的移动都是合理的
::new (&new_data[k]) ValueT(::std::move(this->m_data[k]));
new_size += 1;
}
::new (&new_data[new_size]) ValueT(::std::forward<Args>(args)...);
new_size += 1;
} catch (...) {
destruct_len(new_data, new_size);
::operator delete(new_data);
// 将异常重新抛出
throw;
}
// 将原数据析构
// 如果上面抛出异常了,这里可能把原数据全清了
this->destruct_this();
// 接管所有权
this->m_data = new_data;
this->m_size = new_size;
this->m_capacity = new_capacity;
return new_data[new_size];
}
private:
// 其实是析构的一个抽象
void destruct_this() noexcept {
this->clear();
::operator delete(this->m_data);
}
void destruct_len(ValueT* pdata, ::size_t len) noexcept {
for (::size_t k = 0; k < len; k += 1) {
pdata[k].~ValueT();
}
}
};
} // namespace my
int main() {
::my::vector<::std::string> vec;
vec.push_back("hello");
vec.emplace_back();
vec.emplace_back("hello", 4);
// 标准不禁止
// vec.emplace_back(vec[0]);
for (const auto& str : vec) {
::std::cout << str << ::std::endl;
}
return 0;
}