C++ 自定义指针类型和容器/分配器类型定义
C++标准容器和分配器为容器使用的指针类型提供typedef,即:C++ 自定义指针类型和容器/分配器类型定义,c++,c++11,C++,C++11,C++标准容器和分配器为容器使用的指针类型提供typedef,即: typename std::vector<T>::pointer typename std::vector<T>::const_pointer 由于每个容器也有一个value\u类型typedef,因此指针typedef的用途大概是用于某些奇怪的情况,其中使用的指针类型不是value\u类型*。我个人从未见过这样的用例,但我想标准委员会希望提供在容器中使用自定义指针类型的可能性 问题在于,这似乎与std
typename std::vector<T>::pointer
typename std::vector<T>::const_pointer
由于每个容器也有一个value\u类型
typedef,因此指针
typedef的用途大概是用于某些奇怪的情况,其中使用的指针类型不是value\u类型*
。我个人从未见过这样的用例,但我想标准委员会希望提供在容器中使用自定义指针类型的可能性
问题在于,这似乎与std::allocator\u traits
中为函数提供的定义不一致。具体地说,在std::allocator\u traits
中,我们有构造
函数,其定义如下:
template <class T, class... Args>
static void construct(Alloc& a, T* p, Args&&... args);
如果没有这一点,使用std::allocator\u traits::construct
的容器如果与定义某些自定义指针类型的分配器一起使用,则可能会失败
那么,这是怎么回事?或者我误解了使用
指针typedef的初衷吗?这种二分法是有目的的,不会产生问题。construct
成员函数通常是这样实现的:
template <class U, class ...Args>
void
construct(U* p, Args&& ...args)
{
::new(static_cast<void*>(p)) U(std::forward<Args>(args)...);
}
因此,最终您需要一个“真正的”指针来调用新的。为了传递需要构造的对象的类型,只需在指针类型中传递该信息(例如,U*
)
对于对称性,destroy
也用实际指针表示,通常实现如下:
template <class U>
void
destroy(U* p)
{
p->~U();
}
2.
到原始指针(p);//其中:
template <class T>
inline
T*
to_raw_pointer(T* p) noexcept
{
return p;
}
template <class Pointer>
inline
typename std::pointer_traits<Pointer>::element_type*
to_raw_pointer(Pointer p) noexcept
{
return ::to_raw_pointer(p.operator->());
}
模板
内联
T*
到原始指针(T*p)无异常
{
返回p;
}
模板
内联
typename std::指针\特征::元素\类型*
to_原始_指针(指针p)无异常
{
return::to_raw_指针(p.operator->());
}
这将调用指针
的运算符->()
,它将直接返回T*
,或转发到直接或间接返回T*
的对象。所有指针
类型都应支持运算符->()
,即使它引用的是布尔值
。这种技术的一个缺点是,除非指针
是可撤销的,否则当前不需要调用操作符->()
。该标准应取消这一限制
在C++14中,第二个重载的返回类型(实际上是两个重载)可以方便地替换为auto
如果您有一个T*
并希望构造一个指针,那么您就运气不好了。在这个方向上没有可移植的转换方式
还要注意vector::data()
成员函数的返回类型。它在value\u-type*
,指针
之间来回跳转,并且当前(有目的地)将value\u-type*
构造
固定到元素类型。同样地,销毁
<代码>分配
和取消分配
不可用。allocate
和deallocate
都指向您正在检查的指针类型。这两个函数都不处理实际的对象构造和破坏,因此不保证固定到类型T
。然而,构造和销毁,都是如此。@dyp::std::addressof(*p)
,而不是;)pointer!=值类型*
似乎已经(某种程度上)在C++11中引入。据我所知,在C++03中,容器实现者可以假定指针==value\u type*
。我目前正在搜索关于它为什么被改变的建议。这似乎与分配器概念文件(N2654)和可能的作用域分配器模型(N2554)有关。在重新阅读这些文件后,似乎删除了指针==value\u type*
的限制。这可能与使用smart/fancy指针有关,例如用于共享内存分配器。我的意思是,在标准中应该放宽这一要求。谢谢,我将澄清我粗心的语言。“因此,最终您需要一个“真正的”指针来调用placement new。”但毫无疑问,分配器应该知道如何从指针中获取T*
。。那么,为什么不由分配器负责进行转换/提取呢?这对分配器的API来说是一个不必要的补充。事实上,C++98/03分配器实际上在address
成员函数中有这样一个API,而这一要求只是为了更有用的独立实用程序std::addressof()
而放弃了。在我对OP的评论中,我推测了指针算法。据我所见,指针
不需要支持指针算法,因此除了数组的第一个位置之外,不可能在任何位置构造元素-正如您所说,不可能从T*
转换回指针
。这可能是另一个原因吗?@dyp:不,我不这么认为。[allocator.requirements]/p5部分说:X::pointer
和X::const_pointer
也应满足随机访问迭代器(24.2)的要求。这需要指针运算。
void* operator new (std::size_t size, void* ptr) noexcept;
template <class U>
void
destroy(U* p)
{
p->~U();
}
template <class T> T* addressof(T& r) noexcept;
template <class T>
inline
T*
to_raw_pointer(T* p) noexcept
{
return p;
}
template <class Pointer>
inline
typename std::pointer_traits<Pointer>::element_type*
to_raw_pointer(Pointer p) noexcept
{
return ::to_raw_pointer(p.operator->());
}