C++ Primer第五版练习 16.16

练习 16.16:将StrVec类重写为模板,命名为Vec。
代码:

#include <algorithm>
#include <string>
#include <stdexcept>

template <typename T> class Vec{
	friend bool operator==(const Vec<T> &lhs, const Vec<T> &rhs) {
		if (lhs.size() != rhs.size())
			return false;
		auto p = lhs.elements, p1 = rhs.elements;
		while (p != lhs.first_free) {
			if (*p++ != *p1++) return false;
		}
		return true;
	}
	friend bool operator!=(const Vec<T> &lhs, const Vec<T> &rhs) {
		return !(lhs == rhs);
	}
	friend bool operator<(const Vec<T> &lhs, const Vec<T> &rhs) {
		auto p = lhs.elements, p1 = rhs.elements;
		while (p != lhs.end() && p1 != rhs.end()) {
			if (*p != *p1) return *p < *p1;
			++p, ++p1;
		}
		return p == lhs.end() && p1 != rhs.end() ? true : false;
	}
public:
	Vec():
		elements(nullptr), first_free(nullptr), cap(nullptr) { }
	Vec(const Vec &);
	Vec(Vec &&) noexcept;
	Vec(const std::initializer_list<T> &);
	Vec(std::size_t n);
	Vec(std::size_t n, const T &val);
	~Vec();
	Vec &operator=(const Vec &);
	Vec &operator=(Vec &&) noexcept;
	Vec &operator=(const std::initializer_list<T> &);
	T &operator[](std::size_t n) {
		check(n, "out of range");
		return *(elements + n);
	}
	const T &operator[](std::size_t n) const {
		check(n, "out of range");
		return *(elements + n);
	}
	void push_back(const T &);
	size_t size() const {
		return first_free - elements;
	}
	size_t capacity() const {
		return cap - elements;
	}
	void reserve(std::size_t);
	void resize(std::size_t);
	void resize(std::size_t, const T &);
	void construct_each(T *&, T *, const T &);
	T *begin()const {
		return elements;
	}
	T *end()const {
		return first_free;
	}
private:
	static std::allocator<T> alloc;
	void chk_n_alloc() {
		if (size() == capacity())
			reallocate();
	}
	std::pair<T *, T *> alloc_n_copy(const T *, const T *);
	void free();
	void reallocate();
	void allocate_and_construct(std::size_t);
	void check(std::size_t i, const std::string &msg) const;
	T *elements;
	T *first_free;
	T *cap;
};

template<typename T>
Vec<T>::Vec(const Vec &v) {
	auto newdata = alloc_n_copy(v.begin(), v.end());
	elements = newdata.first;
	first_free = cap = newdata.second;
}

template<typename T>
Vec<T>::Vec(Vec &&v) noexcept :
	elements(v.elements), first_free(v.first_free), cap(v.cap) {
	v.elements = v.first_free = v.cap = nullptr;
}

template<typename T>
Vec<T>::Vec(const std::initializer_list<T> &il) {
	auto newdata = alloc_n_copy(il.begin(), il.end());
	elements = newdata.first;
	first_free = cap = newdata.second;
}

template<typename T>
Vec<T>::Vec(std::size_t n) : Vec(n, T()) { }


template<typename T>
Vec<T>::Vec(std::size_t n, const T &val) {
	allocate_and_construct(n);
	construct_each(first_free, elements + n, val);
}

template<typename T>
Vec<T>::~Vec() {
	free();
}

template<typename T>
Vec<T> &Vec<T>::operator=(const Vec &v) {
	auto data = alloc_n_copy(v.begin(), v.end());
	free();
	elements = data.first;
	first_free = cap = data.second;
	return *this;
}

template<typename T>
Vec<T> &Vec<T>::operator=(Vec &&v) noexcept{
	if (this != &v) {
		free();
		elements = v.elements;
		first_free = v.first_free;
		cap = v.cap;
		v.elements = v.first_free = v.cap = nullptr;
	}
}

template<typename T>
Vec<T> &Vec<T>::operator=(const std::initializer_list<T> &il) {
	auto data = alloc_n_copy(il.begin(), il.end());
	free();
	elements = data.first;
	first_free = cap = data.second;
	return *this;
}

template<typename T>
void Vec<T>::push_back(const T &val) {
	chk_n_alloc();
	alloc.construct(first_free++, val);
}

template<typename T>
void Vec<T>::reserve(std::size_t n) {
	if (n > capacity()) {
		allocate_and_construct(n);
	}
}

template<typename T>
void Vec<T>::resize(std::size_t n) {
	resize(n, T());
}

template<typename T>
void Vec<T>::resize(std::size_t n, const T &val) {
	if (n < size()) {
		while (first_free != elements + n) {
			alloc.destroy(--first_free);
		}
	} else if (n > capacity()) {
		allocate_and_construct((3 * n + 1) / 2);
		construct_each(first_free, elements + n, val);
	} else if (n > size()) {
		construct_each(first_free, elements + n, val);
	}
}

template<typename T>
void Vec<T>::construct_each(T *&begin, T *end, const T &newVal) {
	uninitialized_fill(begin, end, newVal);
	begin = end;
}

template<typename T>
std::pair<T *, T *> Vec<T>::alloc_n_copy(const T *b, const T *e) {
	auto data = alloc.allocate(e - b);
	return { data, uninitialized_copy(b, e, data) };
}

template<typename T>
void Vec<T>::free() {
	if (elements) {
		for (auto p = first_free; p != elements;) {
			alloc.destroy(--p);
		}
		alloc.deallocate(elements, cap - elements);
	}
}

template<typename T>
void Vec<T>::reallocate() {
	auto newcapacity = size() ? (3 * size() + 1) / 2 : 1;
	allocate_and_construct(newcapacity);
}

template<typename T>
void Vec<T>::allocate_and_construct(std::size_t newcapacity) {
	auto first = alloc.allocate(newcapacity);
	auto last = std::uninitialized_copy(std::make_move_iterator(begin()), std::make_move_iterator(end()), first);
	free();
	elements = first;
	first_free = last;
	cap = elements + newcapacity;
}

template<typename T>
void Vec<T>::check(std::size_t i, const std::string &msg) const {
	if (size() <= i) {
		throw std::out_of_range(msg);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值