【问题标题】:custom Allocator compilation difficulties 4 [closed]自定义分配器编译困难4 [关闭]
【发布时间】:2014-07-04 17:15:47
【问题描述】:

我开始感到不舒服,如果为了编译一些简单的代码我必须向尊敬的听众提出 4 个问题。但根据我的经验,自定义分配器参数似乎是最困难的。 我已经定义了一个非常非常简单的自定义分配器。 我有一个 typedef Char 可能是 char,char16_t,char32_t 。

我定义了一个作为 basic_string 实例化的字符串。 我定义了该类的实例,代码正确地将它们分配到自定义内存(名为 m 的数组 - 您可以在调试器中看到它)。 该代码适用于各种尺寸。通过阅读basic_string的代码和查看内存排列,可以理解basic_strings的实例只是指向已分配内存的指针。 我也将 Vector 定义为:vector<Char>。 问题在于,有时向量会节省自定义内存,而有时则不会。是错误还是我不懂基本概念?

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;
}

【问题讨论】:

  • 您能否添加一些痕迹,以便我们可以看到预期和实际结果/副作用?请注意,std::string 通常使用小字符串优化,其中对于短字符串,不使用分配器。
  • @dyp 我一开始就解释过了。当你写: Vector vv={U'a',U'b',U'c',... } 你期望上面的值会进入 Vector 但他们不会。内存指针得到了正确处理,但没有写入任何内容。取而代之的是 vv[0]=U'a' 可以正常工作,并且 vv[1]=U'b' 也可以正常工作。相反, vv.push_back 正确处理分配和指针,但不向内存写入任何内容。如果您需要更详细的信息,请告诉我具体该怎么做。
  • 你的construct 没有构造,它什么都不做。因此向量元素的初始化失败。
  • @dyp 通常? g++clang 似乎没有实现它,因为 sizeof(std::string)sizeof(char *) 相同。
  • 如果你实现construct,这符合我的预期。

标签: c++ memory-management


【解决方案1】:

您的construct 没有构造,它什么也不做。随之而来的是向量元素的初始化失败。你需要

::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-&gt;~T();

【讨论】:

    【解决方案2】:

    感谢您的提示和解决方案。

    我不明白的是,当这些东西不仅仅是只需要一些副本的 POD(普通旧数据)时,应该使用“构造”来“构造”东西。 (如有错误请指正)。

    所以我认为问题的正确解决方案是注释掉“构造”,因为我只需要默认行为。我做到了,它按预期工作。

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

    【讨论】:

    猜你喜欢
    • 2014-12-08
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-10
    • 1970-01-01
    相关资源
    最近更新 更多