简体   繁体   English

为结构数组分配内存块

[英]Allocate chunk of memory for array of structs

I need an array of this struct allocated in one solid chunk of memory. 我需要在一个坚实的内存块中分配这个结构的数组。 The length of "char *extension" and "char *type" are not known at compile time. “char * extension”和“char * type”的长度在编译时是未知的。

struct MIMETYPE
{
 char *extension;
 char *type;
};

If I used the "new" operator to initialize each element by itself, the memory may be scattered. 如果我使用“new”运算符来自己初始化每个元素,则内存可能会分散。 This is how I tried to allocate a single contiguous block of memory for it: 这就是我尝试为它分配一个连续的内存块的方法:

//numTypes = total elements of array
//maxExtension and maxType are the needed lengths for the (char*) in the struct
//std::string ext, type;
unsigned int size = (maxExtension+1 + maxType+1) * numTypes;
mimeTypes = (MIMETYPE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);

But, when I try to load the data in like this, the data is all out of order and scattered when I try to access it later. 但是,当我尝试像这样加载数据时,当我稍后尝试访问时,数据全部乱序并且分散。

for(unsigned int i = 0; i < numTypes; i++)
{
 //get data from file
 getline(fin, line);
 stringstream parser.str(line);
 parser >> ext >> type;

 //point the pointers at a spot in the memory that I allocated
 mimeTypes[i].extension = (char*)(&mimeTypes[i]);
 mimeTypes[i].type = (char*)((&mimeTypes[i]) + maxExtension);

 //copy the data into the elements
 strcpy(mimeTypes[i].extension, ext.c_str());
 strcpy(mimeTypes[i].type, type.c_str());
}

can anyone help me out? 谁能帮我吗?

EDIT: 编辑:

unsigned int size = (maxExtension+1 + maxType+1);
mimeTypes = (MIMETYPE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size * numTypes);

for(unsigned int i = 0; i < numTypes; i++)
    strcpy((char*)(mimeTypes + (i*size)), ext.c_str());
    strcpy((char*)(mimeTypes + (i*size) + (maxExtension+1)), type.c_str());

You mix 2 allocation: 你混合2分配:

1) manage array of MIMETYPE and 1)管理MIMETYPE和

2) manage array of characters 2)管理字符数组

May be (I don't really understand your objectives): 可能(我真的不明白你的目标):

struct MIMETYPE
{
    char extension[const_ofmaxExtension];
    char type[maxType];
};

would be better to allocate linear items in form: 最好在表单中分配线性项:

new MIMETYPE[numTypes];

I'll put aside the point that this is premature optimization (and that you ought to just use std::string, std::vector, etc), since others have already stated that. 我会撇开这是过早优化的意义(并且你应该只使用std :: string,std :: vector等),因为其他人已经说过了。

The fundamental problem I'm seeing is that you're using the same memory for both the MIMETYPE structs and the strings that they'll point to. 我看到的根本问题是你对MIMETYPE结构和它们指向的字符串使用相同的内存。 No matter how you allocate it, a pointer itself and the data it points to cannot occupy the exact same place in memory. 无论你如何分配它,指针本身和它指向的数据都不能占据内存中完全相同的位置。


Lets say you needed an array of 3 types and had MIMETYPE* mimeTypes pointing to the memory you allocated for them. 假设您需要一个包含3种类型的数组,并且MIMETYPE* mimeTypes指向您为其分配的内存。

That means you're treating that memory as if it contains: 这意味着你将内存视为包含:

8 bytes: mime type 0
8 bytes: mime type 1
8 bytes: mime type 2

Now, consider what you're doing in this next line of code: 现在,考虑您在下一行代码中正在做的事情:

mimeTypes[i].extension = (char*)(&mimeTypes[i]);

extension is being set to point to the same location in memory as the MIMETYPE struct itself. extension被设置为指向与MIMETYPE结构本身相同的内存位置。 That is not going to work. 那不行。 When subsequent code writes to the location that extension points to, it overwrites the MIMETYPE structs. 当后续代码写入extension指向的位置时,它会覆盖MIMETYPE结构。

Similarly, this code: 同样,这段代码:

strcpy((char*)(mimeTypes + (i*size)), ext.c_str());

is writing the string data in the same memory that you otherwise want to MIMETYPE structs to occupy. 将字符串数据写入您想要MIMETYPE结构占用的同一内存中。


If you really want store all the necessary memory in one contiguous space, then doing so is a bit more complicated. 如果你真的想在一个连续的空间中存储所有必要的内存,那么这样做会有点复杂。 You would need to allocate a block of memory to contain the MIMETYPE array at the start of it, and then the string data afterwards. 您需要分配一个内存块以在其开头包含MIMETYPE数组,然后分配字符串数据。

As an example, lets say you need 3 types. 举个例子,假设您需要3种类型。 Lets also say the max length for an extension string (maxExtension) is 3 and the max length for a type string (maxType) is 10. In this case, your block of memory needs to be laid out as: 还可以说扩展字符串(maxExtension)的最大长度为3,类型字符串(maxType)的最大长度为10.在这种情况下,您的内存块需要布局为:

8 bytes: mime type 0
8 bytes: mime type 1
8 bytes: mime type 2
4 bytes: extension string 0
11 bytes: type string 0
4 bytes: extension string 1
11 bytes: type string 1
4 bytes: extension string 2
11 bytes: type string 2

So to allocate, setup, and fill it all correctly you would want to do something like: 因此,要正确分配,设置和填充它,您可能希望执行以下操作:

unsigned int mimeTypeStringsSize = (maxExtension+1 + maxType+1);
unsigned int totalSize = (sizeof(MIMETYPE) + mimeTypeStringsSize) * numTypes;
char* data = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, totalSize);

MIMETYPE* mimeTypes = (MIMETYPE*)data;
char* stringData = data + (sizeof(MIMETYPE) * numTypes);

for(unsigned int i = 0; i < numTypes; i++)
{
    //get data from file
    getline(fin, line);
    stringstream parser.str(line);
    parser >> ext >> type;

    // set pointers to proper locations
    mimeTypes[i].extension = stringData + (mimeTypeStringsSize * i);
    mimeTypes[i].type = stringData + (mimeTypeStringsSize * i) + maxExtension+1;

    //copy the data into the elements
    strcpy(mimeTypes[i].extension, ext.c_str());
    strcpy(mimeTypes[i].type, type.c_str());
}

(Note: I've based my byte layout explanations on typical behavior of 32-bit code. 64-bit code would have more space used for the pointers, but the principle is the same. Furthermore, the actual code I've written here should work regardless of 32/64-bit differences.) (注意:我的字节布局解释基于32位代码的典型行为.64位代码将有更多的空间用于指针,但原理是相同的。此外,我在这里写的实际代码无论32/64位差异都应该工作。)

Add one byte in between strings... extension and type are not \\0-terminated the way do it. 在字符串之间添加一个字节...扩展名和类型不是以0的方式终止。

here you allocate allowing for an extra \\0 - OK 在这里你分配允许额外的\\ 0 - 好的

unsigned int size = (maxExtension+1 + maxType+1) * numTypes;
mimeTypes = (MIMETYPE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);

here you don't leave any room for extension's ending \\0 (if string len == maxExtension) 在这里你不留下任何扩展名结尾的空间\\ 0(如果是字符串len == maxExtension)

 //point the pointers at a spot in the memory that I allocated
 mimeTypes[i].extension = (char*)(&mimeTypes[i]);
 mimeTypes[i].type = (char*)((&mimeTypes[i]) + maxExtension);

instead i think it should be 相反,我认为它应该是

 mimeTypes[i].type = (char*)((&mimeTypes[i]) + maxExtension + 1);

What you need to do is get a garbage collector and manage the heap. 您需要做的是获取垃圾收集器并管理堆。 A simple collector using RAII for object destruction is not that difficult to write. 使用RAII进行对象破坏的简单收集器并不难写。 That way, you can simply allocate off the collector and know that it's going to be contiguous. 这样,您可以简单地分配收集器,并知道它将是连续的。 However, you should really, REALLY profile before determining that this is a serious problem for you. 但是,在确定这对您来说这是一个严重问题之前,您应该真的,真正地进行配置。 When that happens, you can typedef many std types like string and stringstream to use your custom allocator, meaning that you can go back to just std::string instead of the C-style string horrors you have there. 当发生这种情况时,你可以输入许多std类型,比如string和stringstream来使用你的自定义分配器,这意味着你可以回到std :: string而不是你那里的C风格字符串恐怖。

You really have to know the length of extension and type in order to allocate MIMETYPE s contiguously (if "contiguously" means that extension and type are actually allocated within the object). 你必须知道extensiontype的长度,以便连续地分配MIMETYPE (如果“连续”意味着extensiontype实际上是在对象内分配的)。 Since you say that the length of extension and type are not known at compile time, you cannot do this in an array or a vector (the overall length of a vector can be set and changed at runtime, but the size of the individual elements must be known at compile time, and you can't know that size without knowing the length of extension and type ). 因为你说的长度extensiontype没有在编译时已知的,则无法在阵列或为此vector (一个的总长度vector可以被设置并在运行时改变,但是各个元件的尺寸必须在编译时知道,如果不知道extension的长度和type ,你就无法知道这个大小)。

I would personally recommend using a vector of MIMETYPE s, and making the extension and type fields both string s. 我个人建议使用MIMETYPEvector ,并使extensiontype字段都为string s。 You're requirements sound suspiciously like premature optimization guided by a gut feeling that dereferencing pointers is slow, especially if the pointers cause cache misses. 你的要求听起来很可疑,就像过早的优化一样,直觉导致解除引用指针很慢,特别是如果指针导致缓存未命中。 I wouldn't worry about that until you have actual data that reading these fields is an actual bottleneck. 在您获得读取这些字段的实际数据之前,我不会担心这个问题。

However, I can think of a possible "solution": you can allocate the extension and type strings inside the MIMETYPE object when they are shorter than a particular threshold and allocate them dynamically otherwise: 不过,我能想到的一个可能的“解决方案”:你可以分配的extensiontype的字符串内MIMETYPE对象时,他们比特定阈值更短的和动态分配,否则它们:

#include <algorithm>
#include <cstring>
#include <new>

template<size_t Threshold> class Kinda_contig_string {
    char contiguous_buffer[Threshold];
    char* value;

    public:

    Kinda_contig_string() : value(NULL) { }

    Kinda_contig_string(const char* s)
    {
         size_t length = std::strlen(s);
         if (s < Threshold) {
             value = contiguous_buffer;
         }
         else {
             value = new char[length];
         }

         std::strcpy(value, s);
    }

    void set(const char* s)
    {
        size_t length = std::strlen(s);

        if (length < Threshold && value == contiguous_buffer) {
            // simple case, both old and new string fit in contiguous_buffer
            // and value points to contiguous_buffer
            std::strcpy(contiguous_buffer, s);
            return;
        }

        if (length >= Threshold && value == contiguous_buffer) {
            // old string fit in contiguous_buffer, new string does not
            value = new char[length];
            std::strcpy(value, s);
            return;
        }

        if (length < Threshold && value != contiguous_buffer) {
            // old string did not fit in contiguous_buffer, but new string does
            std::strcpy(contiguous_buffer, s);
            delete[] value;
            value = contiguous_buffer;
            return;
        }

        // old and new strings both too long to fit in extension_buffer
        // provide strong exception guarantee
        char* temp_buffer = new char[length];
        std::strcpy(temp_buffer, s);
        std::swap(temp_buffer, value);
        delete[] temp_buffer;
        return;
    }

    const char* get() const
    {
        return value;
    }
}

class MIMETYPE {
    Kinda_contig_string<16> extension;
    Kinda_contig_string<64> type;

  public:
    const char* get_extension() const
    {
        return extension.get();
    }

    const char* get_type() const
    {
        return type.get();
    }

    void set_extension(const char* e)
    {
        extension.set(e);
    }

    // t must be NULL terminated
    void set_type(const char* t)
    {
        type.set(t);
    }

    MIMETYPE() : extension(), type() { }

    MIMETYPE(const char* e, const char* t) : extension(e), type(t) { }
};

I really can't endorse this without feeling guilty. 我真的不能在不感到愧疚的情况下赞同这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM