C++ 分配连续内存是否需要标准分配器?
我在C++11标准中找不到任何关于是否需要符合标准的分配器返回指向连续内存块的指针的指示C++ 分配连续内存是否需要标准分配器?,c++,memory-management,c++11,C++,Memory Management,C++11,我在C++11标准中找不到任何关于是否需要符合标准的分配器返回指向连续内存块的指针的指示 std::vector(23.3.6.1/1)上的连续存储要求似乎暗示了这一点(否则,似乎无法将std::vector与符合标准的任意分配器一起使用)。但任何澄清都是最受欢迎的 一个等价的问题是:通过指针算法(可能是在转换了 >代码> >的普通的指针> < /C> >之后,我是否总是可以移动通过代码>返回的内存块(例如,如前面描述的一个普通的原始C++指针)?< /P> < P>是的,它必须是连续的,从某
std::vector
(23.3.6.1/1)上的连续存储要求似乎暗示了这一点(否则,似乎无法将std::vector
与符合标准的任意分配器一起使用)。但任何澄清都是最受欢迎的
一个等价的问题是:通过指针算法(可能是在转换了<代码> >代码> <代码> >的普通的<代码>指针> < /C> >之后,我是否总是可以移动通过代码>返回的内存块(例如,如前面描述的一个普通的原始C++指针)?< /P> < P>是的,它必须是连续的,从某种意义上说,
allocator::pointer
上的指针算法按预期工作
仔细想想,返回的内存很少是物理上连续的。它看起来是连续的,因为现代CPU有虚拟内存,并且
X*
在这个虚拟内存中被解释。这取决于你所说的连续
是什么意思。正如您的程序所看到的那样,内存肯定是连续的,或者在计算数组中的偏移量/索引时,它不会“正常工作”,诸如此类。如果分配10个整数值,则希望ptr[0]
为第一个整数值,ptr[9]
为最后一个整数值-由于ptr
只是一个指针,因此它只能指向一个连续的内存块
在引擎盖下,在真实的物理内存中,它可能是连续的,也可能不是连续的——这是由操作系统来决定的,它很可能从“任何地方”为应用程序提供内存 给定一个分配器
A
,我想说A
为A::allocate(n)
,std::addressof(*p)+k==std::addressof(*(p+k))
返回的A::allocate(n)
,std::addressof(*(p+n-1)+=std::addressof(*(*p)+n
我认为分配器要求(§17.6.3.5[分配器要求])中不需要此属性,但我无法想象没有它如何实现vector
(尤其是vector::data()
)。要么(a)分配器要求中缺少某些内容,(b)分配器要求未得到明确规定,要么(c)vector
对其分配器提出了超出一般要求的额外要求
下面是一个不提供连续内存()的分配器的“简单”示例:
#包括
#包括
#包括
#包括
#包括
模板
类ScaledPointer:public std::迭代器{
T*ptr;
公众:
ScaledPointer()=默认值;
缩放指针(T*ptr):ptr(ptr){}
模板
显式ScaledPointer(U*ptr):ptr(static_cast(ptr)){
模板
显式ScaledPointer(常量ScaledPointer和其他):
ptr(static_cast(other.ptr)){}
显式运算符bool()const{return bool{ptr};}
T&运算符*()常数{
返回*ptr;
}
T*运算符->()常量{
返回ptr;
}
运算符[](标准::ptrdiff_T n)常量{
返回ptr[2*n];
}
ScaledPointer和运算符++(){
ptr+=2;
归还*这个;
}
ScaledPointer运算符++(int){
缩放指针tmp(*此);
++*这,;
返回tmp;
}
缩放指针和运算符--(){
ptr-=2;
归还*这个;
}
ScaledPointer运算符--(int){
缩放指针tmp(*此);
--*这,;
返回tmp;
}
模板
friend bool运算符==(常量缩放指针&u,常量缩放指针&v){
返回u.ptr==v.ptr;
}
模板
友元布尔运算符!=(常量缩放指针&u,常量缩放指针&v){
返回!(u==v);
}
模板
friend布尔运算符<(常量缩放指针&u,常量缩放指针&v){
返回u.ptr(常量缩放指针&u,常量缩放指针&v){
返回vstd::cout-Erm,否则它将如何使存储可用?分配器甚至还可以返回什么类型的指针?如何返回指向非连续内存块的指针?@Xeo:也许您返回某种碎片存储,您可以使用提供的指针类型来导航它?它必须返回指向请求的指针存储的TED量,而不是某些结构。@ R.MARTHANHOFENANDEANS读部分7.63.5的C++ 11标准必须是<代码> x:指针< /C> >类型,默认情况下是指针,但不是必须的。@ BBOTFISH:C++标准没有正式指定所有的东西,但它遵循的事实是:<代码>分配器::构造(指针,VALL)
必须处理由allocator::allocate
返回的指针。因为allocate
可以为多个元素返回内存(非常有意),这些附加元素位于指针+1,poi
#include <cstddef>
#include <iostream>
#include <iterator>
#include <limits>
#include <memory>
template <typename T>
class ScaledPointer : public std::iterator<std::random_access_iterator_tag, T> {
T* ptr;
public:
ScaledPointer() = default;
ScaledPointer(T* ptr) : ptr(ptr) {}
template <typename U>
explicit ScaledPointer(U* ptr) : ptr(static_cast<T*>(ptr)) {}
template <typename U>
explicit ScaledPointer(const ScaledPointer<U>& other) :
ptr(static_cast<T*>(other.ptr)) {}
explicit operator bool () const { return bool{ptr}; }
T& operator * () const {
return *ptr;
}
T* operator -> () const {
return ptr;
}
T& operator [] (std::ptrdiff_t n) const {
return ptr[2 * n];
}
ScaledPointer& operator ++ () {
ptr += 2;
return *this;
}
ScaledPointer operator ++ (int) {
ScaledPointer tmp(*this);
++*this;
return tmp;
}
ScaledPointer& operator -- () {
ptr -= 2;
return *this;
}
ScaledPointer operator -- (int) {
ScaledPointer tmp(*this);
--*this;
return tmp;
}
template <typename U, typename V>
friend bool operator == (const ScaledPointer<U>& u, const ScaledPointer<V>& v) {
return u.ptr == v.ptr;
}
template <typename U, typename V>
friend bool operator != (const ScaledPointer<U>& u, const ScaledPointer<V>& v) {
return !(u == v);
}
template <typename U, typename V>
friend bool operator < (const ScaledPointer<U>& u, const ScaledPointer<V>& v) {
return u.ptr < v.ptr;
}
template <typename U, typename V>
friend bool operator > (const ScaledPointer<U>& u, const ScaledPointer<V>& v) {
return v < u;
}
template <typename U, typename V>
friend bool operator <= (const ScaledPointer<U>& u, const ScaledPointer<V>& v) {
return !(v < u);
}
template <typename U, typename V>
friend bool operator >= (const ScaledPointer<U>& u, const ScaledPointer<V>& v) {
return !(u < v);
}
ScaledPointer& operator += (std::ptrdiff_t n) {
ptr += 2 * n;
return *this;
}
friend ScaledPointer operator + (const ScaledPointer& u, std::ptrdiff_t n) {
ScaledPointer tmp = u;
tmp += n;
return tmp;
}
ScaledPointer& operator -= (std::ptrdiff_t n) {
ptr -= 2 * n;
return *this;
}
friend ScaledPointer operator - (const ScaledPointer& u, std::ptrdiff_t n) {
ScaledPointer tmp = u;
tmp -= n;
return tmp;
}
friend std::ptrdiff_t operator - (const ScaledPointer& a, const ScaledPointer& b) {
return (a.ptr - b.ptr) / 2;
}
};
template <typename T>
class ScaledAllocator {
public:
typedef ScaledPointer<T> pointer;
typedef T value_type;
typedef std::size_t size_type;
pointer allocate(size_type n) {
const std::size_t size = (n * (2 * sizeof(T)));
void* p = ::operator new(size);
std::cout << __FUNCTION__ << '(' << n << ") = " << p << std::endl;
std::fill_n((unsigned*)p, size / sizeof(unsigned), 0xFEEDFACEU);
return pointer{p};
}
void deallocate(pointer p, size_type n) {
std::cout << __FUNCTION__ << '(' << &*p << ", " << n << ')' << std::endl;
::operator delete(&*p);
}
static size_type max_size() {
return std::numeric_limits<size_type>::max() / 2;
}
template <typename U, typename V>
friend bool operator == (const ScaledAllocator<U>&, const ScaledAllocator<V>&) {
return true;
}
template <typename U, typename V>
friend bool operator != (const ScaledAllocator<U>&, const ScaledAllocator<U>&) {
return false;
}
};
#include <algorithm>
#include <vector>
int main() {
using namespace std;
cout << hex << showbase;
vector<unsigned, ScaledAllocator<unsigned>> vec = {0,1,2,3,4};
for_each(begin(vec), end(vec), [](unsigned i){ cout << i << ' '; });
cout << endl;
auto p = vec.data();
for(auto i = decltype(vec.size()){0}, n = vec.size(); i < n; ++i)
cout << p[i] << ' ';
cout << endl;
}