gpt4 book ai didi

c++ - 公开 std::vector 接口(interface)的任何更好的方法?

转载 作者:搜寻专家 更新时间:2023-10-31 00:36:49 24 4
gpt4 key购买 nike

我正在编写一个 std::vector 包装器,它使用自定义分配器通过 .dll 与 PascalScript 解释器进行通信。下面的代码工作得很好,但更新和编写起来非常乏味,而且会伤到我的眼睛。

此解释器中的数组与其大小连续存储在 &Array_Ptr[0] - sizeof(int) 中。

想要对这些数组使用 std::vector,我决定编写一个自定义分配器来分配 size + sizeof(int) 并让 vector 包装器将大小在 ptr[0]。因此,数据存储在 &ptr[0] + sizeof(int) 中。

问题是,如果我想使用 vector 接口(interface),我必须手动写出所有 std::vector 的 函数,因为从它继承是不好的?

我想出了以下代码:

template<typename T>
class PascalAllocator : public BasicAllocator<T> //BasicAllocator is equivalent to std::allocator with minor changes.
{
public:
typedef typename BasicAllocator<T>::pointer pointer;
typedef typename BasicAllocator<T>::size_type size_type;
typedef typename BasicAllocator<T>::value_type value_type;

template<typename U>
struct rebind {typedef PascalAllocator<U> other;};

pointer allocate(size_type n, const void* hint = 0)
{
std::int32_t* data_ptr = reinterpret_cast<std::int32_t*>(::operator new((n * sizeof(value_type)) + sizeof(std::int32_t)));
return reinterpret_cast<pointer>(++data_ptr);
}

void deallocate(void* ptr, size_type n)
{
if (ptr)
{
std::int32_t* data_ptr = reinterpret_cast<std::int32_t*>(ptr);
::operator delete(reinterpret_cast<T*>(--data_ptr));
}
}
};

template<typename T, typename Allocator = PascalAllocator<T>>
class PascalVector
{
private:
std::vector<T, Allocator> Data;
inline std::int32_t* size_ptr() {return reinterpret_cast<std::int32_t*>(&Data[0]) - 1;}
inline const std::int32_t* size_ptr() const {return reinterpret_cast<std::int32_t*>(&Data[0]) - 1;}

public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
typedef typename std::vector<T, Allocator>::iterator iterator;
typedef typename std::vector<T, Allocator>::const_iterator const_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;

explicit PascalVector(const Allocator& alloc = Allocator()) : Data(std::forward<decltype(alloc)>(alloc)) {*size_ptr() = 0;}
explicit PascalVector(size_type size, const Allocator& alloc = Allocator()) : Data(size, std::forward<decltype(alloc)>(alloc)) {*size_ptr() = size - 1;}
explicit PascalVector(size_type size, const T &value, const Allocator& alloc = Allocator()) : Data(size, std::forward<decltype(value)>(value), std::forward<decltype(alloc)>(alloc)) {*size_ptr() = size - 1;}

template<class InputIt>
PascalVector(InputIt first, InputIt second, const Allocator &alloc = Allocator()) : Data(first, second, std::forward<decltype(alloc)>(alloc)) {*size_ptr() = Data.size() - 1;}

PascalVector(const PascalVector &other) : Data(other.Data) {}
PascalVector(const PascalVector &other, const Allocator& alloc) : Data(other.Data, std::forward<decltype(alloc)>(alloc)) {}
PascalVector(PascalVector && other) : Data(std::move(other.Data)) {}
PascalVector(PascalVector && other, const Allocator& alloc) : Data(std::move(other.Data), std::move(alloc)) {}
PascalVector(const std::initializer_list<T> &init, const Allocator& alloc = Allocator()) : Data(init, alloc) {}

inline PascalVector& operator = (PascalVector other) {Data.operator = (std::forward<decltype(other.Data)>(other.Data)); return *this;}
inline PascalVector& operator = (std::initializer_list<T> ilist) {Data.operator = (std::forward<decltype(ilist)>(ilist)); return *this;}
inline PascalVector& operator = (PascalVector && other) {Data.operator = (std::forward<decltype(other.Data)>(other.Data)); return *this;}

template<class InputIt>
inline void assign(InputIt first, InputIt second) {Data.assign(first, second);};
inline void assign(size_type count, const T& value) {Data.assign(count, std::forward<decltype(value)>(value));}
inline void assign(std::initializer_list<T> ilist) {Data.assign(std::forward<decltype(ilist)>(ilist));}
inline Allocator get_allocator() const {return Data.get_allocator();}

inline reference at(size_type pos) {return Data.at(pos);}
inline const_reference at(size_type pos) const {return Data.at(pos);}
inline reference operator[](size_type pos) {return Data[pos];}
inline const_reference operator[](size_type pos) const {return Data[pos];}
inline reference front() {return Data.front();}
inline constexpr const_reference front() const {return Data.front();}
inline reference back() {return Data.back();}
inline constexpr const_reference back() const {return Data.back();}
inline pointer data() {return Data.data();}
inline const_pointer data() const {return Data.data();}

inline iterator begin() {return Data.begin();}
inline const_iterator begin() const {return Data.begin();}
inline const_iterator cbegin() const {return Data.cbegin();}
inline iterator end() {return Data.end();}
inline const_iterator end() const {return Data.end();}
inline const_iterator cend() const {return Data.cend();}
inline reverse_iterator rbegin() {return Data.rbegin();}
inline const_reverse_iterator rbegin() const {return Data.rbegin();}
inline const_reverse_iterator crbegin() const {return Data.rbegin();}
inline reverse_iterator rend() {return Data.rend();}
inline const_reverse_iterator rend() const {return Data.rend();}
inline const_reverse_iterator crend() const {return Data.crend();}

inline bool empty() const {return Data.empty();}
inline size_type size() const {return Data.size();}
inline size_type max_size() const {return Data.max_size();}
inline void reserve(size_type new_cap) {Data.reserve(size);}
inline size_type capacity() const {return Data.capacity();}
inline void shrink_to_fit() {Data.shrink_to_fit(); *size_ptr() = Data.size() - 1;}

inline void clear() {Data.clear(); *size_ptr() = 0;}

inline iterator insert(iterator pos, const T& value) {return Data.insert(pos, std::forward<decltype(value)>(value)); *size_ptr() = Data.size() - 1;}
inline void insert(iterator pos, size_type count, const T& value) {Data.insert(pos, count, std::forward<decltype(value)>(value)); *size_ptr() = Data.size() - 1;}
template<class InputIt>
inline void insert(iterator pos, InputIt first, InputIt last) {Data.insert(pos, first, last); *size_ptr() = Data.size() - 1;}
inline void insert(iterator pos, std::initializer_list<T> ilist) {Data.insert(pos, std::forward<decltype(ilist)>(ilist)); *size_ptr() = Data.size() - 1;}

template<class... Args>
inline iterator emplace(iterator pos, Args && ... args) {iterator res = Data.emplace(pos, std::forward<Args>(args)...); *size_ptr() = Data.size() - 1; return res;}
template<class... Args>
inline void emplace_back(Args && ... args) {Data.emplace_back(std::forward<Args>(args)...); *size_ptr() = Data.size() - 1;}

inline iterator erase(iterator pos) {iterator res = Data.erase(pos); *size_ptr() = Data.size(); return res;}
inline iterator erase(iterator first, iterator last) {iterator res = Data.erase(first, last); *size_ptr() = Data.size() - 1; return res;}

inline void push_back(const T& value) {Data.push_back(std::forward<decltype(value)>(value)); *size_ptr() = Data.size() - 1;}
inline void push_back(T && value) {Data.push_back(std::forward<T>(value)); *size_ptr() = Data.size() - 1;}
inline void pop_back() {Data.pop_back(); *size_ptr() = Data.size() - 1;}

inline void resize(size_type count, T value = T()) {Data.resize(count, std::forward<decltype(value)>(value)); *size_ptr() = count - 1;}
inline void swap(PascalVector& other) {Data.swap(other.Data);}
};

现在 PascalAllocator 没问题了。令我恼火的是 PascalVector 接口(interface)。

有什么更简单的方法吗?



编辑:

根据我收到的一些回复,我尝试按如下方式实现我自己的 vector :

template<typename T, typename Allocator = PascalAllocator<T>>
class PSArray : private Allocator
{
private:
typename Allocator::pointer first;
typename Allocator::pointer last;
typename Allocator::size_type _size;
typename Allocator::pointer allocmem(typename Allocator::size_type n, const T& value);
void deallocmem();

public:
typedef T value_type;
typedef typename Allocator::pointer pointer;
typedef typename Allocator::const_pointer const_pointer;
typedef typename Allocator::reference reference;
typedef typename Allocator::const_reference const_reference;
typedef typename Allocator::size_type size_type;
typedef typename Allocator::difference_type difference_type;
typedef typename Allocator::pointer iterator;
typedef typename Allocator::const_pointer const_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef Allocator allocator_type;

allocator_type get_allocator() const {return static_cast<const Allocator&>(*this);}

iterator begin() {return first;}
iterator end() {return last;}
const_iterator begin() const {return first;}
const_iterator end() const {return last;}
size_type size() const {return _size;}

PSArray(size_type n = 0, const T& value = T(), const Allocator& alloc = Allocator());
PSArray(const PSArray &other);
PSArray(PSArray&& other);
~PSArray();

PSArray& operator = (const PSArray &other);
inline reference operator[](size_type pos) {return first[pos];}
inline const_reference operator[](size_type pos) const {return first[pos];}
};

template <class T, class Allocator>
PSArray<T, Allocator>::PSArray(size_type n, const T& value, const Allocator& alloc) : Allocator(alloc), first(0), last(0), _size(0)
{
this->first = this->allocmem(n, value);
this->last = &first[0] + n + 1;
reinterpret_cast<std::int32_t*>(first)[-1] = n - 1; //*(reinterpret_cast<std::int32_t*>(&first[0]) - 1) = n - 1;
_size = n;
}

template <class T, class Allocator>
PSArray<T, Allocator>::PSArray(const PSArray &other) : Allocator(other.get_allocator()), first(0), last(0), _size(other._size)
{
this->first = Allocator::allocate(other._size);
this->last = &first[0] + _size + 1;
memcpy(&first[0], &other.first[0], other._size * sizeof(T));
reinterpret_cast<std::int32_t*>(first)[-1] = _size - 1; //*(reinterpret_cast<std::int32_t*>(&first[0]) - 1) = _size - 1;
}

template <class T, class Allocator>
PSArray<T, Allocator>::PSArray(PSArray&& other) : first(other.first), last(other.last), _size(other._size)
{
other.first = nullptr;
other.last = nullptr;
other._size = 0;
}

template <class T, class Allocator>
PSArray<T, Allocator>::~PSArray()
{
this->deallocmem();
}

template <class T, class Allocator>
PSArray<T, Allocator>& PSArray<T, Allocator>::operator = (const PSArray &other)
{
_size = other._size;
this->first = Allocator::allocate(other._size);
this->last = &first[0] + _size + 1;
memcpy(&first[0], &other.first[0], other._size * sizeof(T));
reinterpret_cast<std::int32_t*>(first)[-1] = _size - 1;
return *this;
}

template <class T, class Allocator>
typename Allocator::pointer PSArray<T, Allocator>::allocmem(typename Allocator::size_type n, const T& value)
{
if (n != 0)
{
size_type i = 0;
typename Allocator::pointer res = Allocator::allocate(n);

try
{
for (i = 0; i < n; ++i)
{
Allocator::construct(res + i, value);
}
}
catch(...)
{
for(size_type j = 0; j < i; ++j)
{
Allocator::destroy(res + j);
}
Allocator::deallocate(res, n);
throw;
}
return res;
}
return nullptr;
}

template <class T, class Allocator>
void PSArray<T, Allocator>::deallocmem()
{
if (first != last)
{
for (iterator i = first; i < last; ++i)
{
Allocator::destroy(i);
}
Allocator::deallocate(first, last - first);
}
}

目前效果还不错。不过,它比以前的代码要多得多。

最佳答案

没有比实现 std::vector 的整个接口(interface)更容易使 PascalVector 看起来像 std::vector 的方法了>.

  • 您不应公开继承 std::vector,因为 std::vector 没有虚拟析构函数,这意味着删除指向 std 的指针: :vector 不会调用 PascalVector 的析构函数,即使指针指向 PascalVector
  • 你不应该私下继承std::vector,因为由于std::vector 中缺少虚函数,你将针对实现进行编程,不是界面。
  • 使用 PascalAllocatorstd::vector typedef 是不够的,因为 PascalAllocator 没有被告知大小的变化 vector (因此无法将大小写入正确的位置)。

顺便说一句:类内定义的函数被自动视为内联inline 关键字在这些情况下是多余的。

关于c++ - 公开 std::vector 接口(interface)的任何更好的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20872029/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com