自定义Allocator编译困难

custom Allocator compilation difficulties 4

本文关键字:编译 Allocator 自定义      更新时间:2023-10-16

我开始觉得不合适了,如果为了编译一些简单的代码,我必须向尊敬的观众提出4个问题。但是,根据我的经验,自定义Allocator参数似乎是最困难的。我已经定义了一个自定义分配器非常非常简单。我有一个类型定义Char可以是Char char16_t char32_t

我定义了一个String,它是basic_string的实例化。我定义了该类的实例,并且代码正确地在自定义内存(名为m的数组-您可以在调试器中看到它)上分配它们。代码在各种尺寸下都能正常工作。通过阅读basic_string的代码并查看内存安排,可以理解basic_string的实例只是指向已分配内存的指针。我把向量定义为:vector<Char>。问题是,有时矢量会节省自定义内存,有时则不会。是bug还是我不懂基本概念?

Vector vv={U'a',U'b',U'c',U'd',U'e',U'f',U'g',U'h'}; // doesn't assigns nothing 
vv[0]=U'a'; // works correctly
vv[1]=U'b'; // works correctly 
for(size_t i=0;vv0[i];i++) 
    vv.push_back(vv0[i]); // doesn't assign nothing.

完整的代码如下:

//#include <bits/c++config.h>
//#define _GLIBCXX_FULLY_DYNAMIC_STRING 1
//#include <stdint.h> //#include <stddef.h> //#include <memory>
#include <iostream>
#include <string>
#include <limits>
#include <vector>
#define CONCAT_PURE(a,b,c) a ## b ## c
#define CONCAT(a,b,c) CONCAT_PURE(a,b,c)
typedef char char8_t; typedef char char64_t; // just for symmetry, char64 may exist when tokens are 64bit.
#define charSz 32 // may be 8,16,32,64 change by hand !
typedef CONCAT(char,charSz,_t) Char; // may be char8_t or char16_t or char32_t or char64_t
// the macro STR(xxxxx) permits us to write strings with characters of 8 bit 16 bit 32 bit (later on 64 bits)
#if charSz == 8
    #define STR(s) #s
#elif charSz == 16
    #define STR(s) u ## #s
#elif charSz == 32
    #define STR(s) U ## #s
#elif charSz == 64
    #define STR(s) UU ## #s
#endif 
typedef int32_t Token;typedef unsigned char byte;
typedef size_t addr;addr freePos=0;Token freeT=0;
const size_t heapSize=0x400;byte m[heapSize];
addr Allocate(size_t sz){addr t=freePos;freePos+=sz;return t;} // justs increasing
void Deallocate(addr p,size_t sz){/**((size_t*)(m+p))=sz;*/} // not important actually
template <typename T>
struct Allocator {
        // http://www.codeproject.com/Articles/4795/C-Standard-Allocator-An-Introduction-and-Implement
typedef T value_type;
typedef T* pointer;             typedef const T* const_pointer;
typedef value_type& reference;  typedef const value_type& const_reference;
typedef std::size_t size_type; typedef std::ptrdiff_t difference_type;
template<typename U> struct rebind{typedef Allocator<U> other;};
        // The initialization of freePos and freeT is done independently of the class definition because doing 
        // it in the class creator another instance (with other template parameter would reinitialize them.
    Allocator() {}
    ~Allocator() {}
    template<typename U> Allocator(U){}
    static inline pointer allocate(size_type n){return (pointer)(m+Allocate(n*sizeof(T)));}
    static void deallocate(pointer p, size_type n){Deallocate((byte*)p-m,sizeof(T)*n);}
    inline size_type max_size() const{return std::numeric_limits<size_type>::max() / sizeof(T);}
    inline void construct(pointer p, const T& t) {}
    inline void destroy(pointer p) {}
};
template <typename T>
    bool operator==(Allocator<T> const &, Allocator<T> const &) { return true; }
template <typename T>
    bool operator!=(Allocator<T> const &, Allocator<T> const &) { return false; }
typedef std::basic_string< Char,std::char_traits<Char>,Allocator<Char> > String;
typedef std::vector< Char,Allocator<Char> > Vector;
int main(){
  // fill memory with values in order to be able to see modifications
    for (size_t i=0;i<sizeof(m);i++) m[i]=0xDD; 
  String s;
  String t;
  String u;
    s=STR(nice);
    t=STR(very beautyfull);
    u=STR(good);

    Char vv0[]=U"looking_well";
    Vector vv={U'a',U'b',U'c',U'd',U'e',U'f',U'g',U'h'};
    vv[0]=U'a';
    vv[1]=U'b';
    for(size_t i=0;vv0[i];i++) 
        vv.push_back(vv0[i]);
    return 0;
}

您的construct不构建,它不做任何事情。由此可见,vector元素的初始化失败。你需要

::new(pointer) T(t);

在某处

我们将其替换为c++ 11风格:

template <class U, class... Args>
void construct(U* ptr, Args&&... args) {
  ::new(ptr) U(std:: forward<Args>(args)...);
}

同样,你的destroy不会破坏。需要p->~T();

谢谢你的提示和解决方案。

我不明白的是,当这些东西不仅仅是POD(普通的旧数据)只需要一些拷贝时,"construct"应该用来"construct"东西。(如果我说错了,请纠正)。

所以我认为这个问题的正确解决方案是注释掉"构造",因为我只需要默认的行为。我照做了,效果如预期。

但是无论如何basic_stringvector之间有一些区别但是因为它适用于basic_string(这意味着基本字符串忽略构造)