每个花哨的指针都应该是一个迭代器吗?
Should every fancy pointer be an iterator?
我正在为C++开发一个基于段的内存分配器。在此分配器中,当您释放内存块时,您必须知道它来自哪个段。因此,我将指向段的指针存储为从分配器的allocate
函数返回的花式pointer
的成员。
只是为了显示我正在谈论的界面:这是支持我的分配器的fancy_memory_resource
......
template<class Ptr>
class fancy_memory_resource {
public:
Ptr allocate(size_t bytes, size_t align = alignof(max_align_t)) {
return do_allocate(bytes, align);
}
void deallocate(Ptr p, size_t bytes, size_t align = alignof(max_align_t)) {
return do_deallocate(p, bytes, align);
}
bool is_equal(const fancy_memory_resource& rhs) const noexcept {
return do_is_equal(rhs);
}
virtual ~fancy_memory_resource() = default;
private:
virtual Ptr do_allocate(size_t bytes, size_t align) = 0;
virtual void do_deallocate(Ptr p, size_t bytes, size_t align) = 0;
virtual bool do_is_equal(const fancy_memory_resource& rhs) const noexcept = 0;
};
(请注意,std::pmr::memory_resource
可以实现为fancy_memory_resource<void*>
的 typedef。这是我故意的。
同时,有问题的Ptr
是一个名为segmented_fancy_pointer<T>
(未附图(的花哨指针类型,它继承自 CRTP 类型fancy_ptr_base<T, segmented_fancy_pointer<T>>
...
template<class T, class CRTP>
struct fancy_ptr_base {
constexpr T *ptr() const noexcept { return m_ptr; }
constexpr explicit operator T*() const noexcept { return ptr(); }
constexpr explicit operator bool() const noexcept { return ptr() != nullptr; }
constexpr bool operator==(CRTP b) const { return ptr() == b.ptr(); }
constexpr bool operator!=(CRTP b) const { return ptr() != b.ptr(); }
constexpr bool operator==(decltype(nullptr)) const { return ptr() == nullptr; }
constexpr bool operator!=(decltype(nullptr)) const { return ptr() != nullptr; }
constexpr bool operator<(CRTP b) const { return ptr() < b.ptr(); }
constexpr bool operator<=(CRTP b) const { return ptr() <= b.ptr(); }
constexpr bool operator>(CRTP b) const { return ptr() > b.ptr(); }
constexpr bool operator>=(CRTP b) const { return ptr() >= b.ptr(); }
constexpr T& operator*() const noexcept { return *ptr(); }
constexpr T* operator->() const noexcept { return ptr(); }
constexpr CRTP& operator+=(ptrdiff_t i) { m_ptr += i; return as_crtp(); }
constexpr CRTP& operator-=(ptrdiff_t i) { m_ptr -= i; return as_crtp(); }
constexpr CRTP& operator++() { ++m_ptr; return as_crtp(); }
constexpr CRTP& operator--() { --m_ptr; return as_crtp(); }
constexpr CRTP operator++(int) { auto r(as_crtp()); ++*this; return r; }
constexpr CRTP operator--(int) { auto r(as_crtp()); --*this; return r; }
constexpr CRTP operator+(ptrdiff_t i) const { auto r(as_crtp()); r += i; return r; }
constexpr CRTP operator-(ptrdiff_t i) const { auto r(as_crtp()); r -= i; return r; }
constexpr ptrdiff_t operator-(CRTP b) const { return ptr() - b.ptr(); }
protected:
T *m_ptr = nullptr;
private:
constexpr CRTP& as_crtp() { return *static_cast<CRTP*>(this); }
constexpr const CRTP& as_crtp() const { return *static_cast<const CRTP*>(this); }
};
template<class CRTP>
struct fancy_ptr_base<void, CRTP> {
constexpr void *ptr() const noexcept { return m_ptr; }
constexpr explicit operator void*() const noexcept { return ptr(); }
constexpr explicit operator bool() const noexcept { return ptr() != nullptr; }
constexpr bool operator==(CRTP b) const { return ptr() == b.ptr(); }
constexpr bool operator!=(CRTP b) const { return ptr() != b.ptr(); }
constexpr bool operator==(decltype(nullptr)) const { return ptr() == nullptr; }
constexpr bool operator!=(decltype(nullptr)) const { return ptr() != nullptr; }
constexpr bool operator<(CRTP b) const { return ptr() < b.ptr(); }
constexpr bool operator<=(CRTP b) const { return ptr() <= b.ptr(); }
constexpr bool operator>(CRTP b) const { return ptr() > b.ptr(); }
constexpr bool operator>=(CRTP b) const { return ptr() >= b.ptr(); }
protected:
void *m_ptr = nullptr;
};
现在是真正的问题。当我将我的segmented_allocator<T>
(未附图(与libc ++的std::vector
一起使用时,一切正常。当我尝试将其与libstdc++的std::vector
一起使用时,它失败了:
In file included from /opt/wandbox/gcc-head/include/c++/8.0.0/bits/stl_algobase.h:67:0,
from /opt/wandbox/gcc-head/include/c++/8.0.0/vector:60,
from prog.cc:1984:
/opt/wandbox/gcc-head/include/c++/8.0.0/bits/stl_iterator.h: In instantiation of 'class __gnu_cxx::__normal_iterator<scratch::segmented_fancy_pointer<int>, std::vector<int, scratch::pmr::propagating_polymorphic_allocator<int, scratch::segmented_fancy_pointer<int> > > >':
/opt/wandbox/gcc-head/include/c++/8.0.0/bits/vector.tcc:105:25: required from 'std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int}; _Tp = int; _Alloc = scratch::pmr::propagating_polymorphic_allocator<int, scratch::segmented_fancy_pointer<int> >; std::vector<_Tp, _Alloc>::reference = int&]'
/opt/wandbox/gcc-head/include/c++/8.0.0/bits/stl_vector.h:954:21: required from 'void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = int; _Alloc = scratch::pmr::propagating_polymorphic_allocator<int, scratch::segmented_fancy_pointer<int> >; std::vector<_Tp, _Alloc>::value_type = int]'
prog.cc:1990:18: required from here
/opt/wandbox/gcc-head/include/c++/8.0.0/bits/stl_iterator.h:770:57: error: no type named 'iterator_category' in 'struct std::iterator_traits<scratch::segmented_fancy_pointer<int> >'
typedef typename __traits_type::iterator_category iterator_category;
^~~~~~~~~~~~~~~~~
现在,我可以通过将"迭代器特征"typedefs添加到fancy_ptr_base<T, CRTP>
来解决此问题,如下所示:
using pointer = CRTP;
using reference = T&;
using value_type = std::remove_cv_t<T>;
using iterator_category = std::random_access_iterator_tag;
using difference_type = ptrdiff_t;
但是我必须这样做吗?是否要求每个花哨的指针类型也是迭代器类型?还是libc++在做正确的事情,而libstdc++的vector
只是有一个错误?
(我已经说服自己,大多数迭代器都不是花哨的指针。这个问题的动机是我突然怀疑也许所有花哨的指针确实都是迭代器。
是的,您需要实现随机访问迭代器的所有要求。 C++标准 [分配器要求]/5:
分配器类型
X
应....X::pointer
和X::const_pointer
还应满足随机访问迭代器的要求。
因此,特别是,您的花哨指针类型需要每个迭代器所需的五种成员类型。
您似乎还缺少fancy_memory_resource<Ptr>::value_type
,几个需要的非成员函数和许多noexcept
关键字。 请仔细查看分配器类型及其指针类型的要求。
- 为什么 C++ std::unordered_map 从 emplace/ 找到返回一个迭代器?
- 为什么我的模板化函数需要从一个迭代器转换到另一个迭代器?
- 转到基于范围的 for 循环中的下一个迭代器
- 有没有一个迭代器的例子,它不会使用 ptrdiff_t 作为其difference_type?
- 每个花哨的指针都应该是一个迭代器吗?
- 如何使用find_if获取最后一个迭代器
- 为什么我无法在C++中将一个迭代器分配给另一个迭代器?
- 递增迭代器以指向另一个迭代器的下一个元素
- 使用一个迭代器迭代向量的向量
- 传入一个迭代器,该迭代器只迭代满足特定条件的元素
- 另一个迭代器引用的对象被另一个迭代器删除
- 使用给定的第一个和最后一个迭代器迭代范围
- 如何从给定另一个迭代器向量的向量中删除元素
- 如何寻址循环中的下一个迭代器并在同一地址插入元素
- 如何编写一个迭代器包装器来组合底层迭代器中的顺序值组
- 我正在尝试为我的 DynamicArray 类创建一个迭代器。为什么 STL 排序不适用于我的迭代器?
- 找到一个位置并返回一个迭代器不起作用
- 存储当前和下一个迭代器
- 谁应该有一个迭代器,我的数据类或该类中的实际列表
- 检查迭代器是否在另一个迭代器之前