2010-07-26 3 views
2

하나의 견고한 메모리 덩어리에 할당 된이 구조체의 배열이 필요합니다. "char * extension"및 "char * type"의 길이는 컴파일시에는 알 수 없습니다.구조체의 배열에 메모리 덩어리를 할당하십시오.

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

"new"연산자를 사용하여 각 요소를 자체적으로 초기화하면 메모리가 흩어질 수 있습니다. 내가 액세스하려고 할 때, 데이터가 모든 순서를 벗어 나는이 같은에서 데이터를로드 할 때,

//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); 

을하지만 흩어져 : 이것은 내가 그것을 위해 메모리를 하나의 연속 된 블록을 할당하려고 시도하는 방법이다 나중에.

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

누구든지 나를 도울 수 있습니까?

편집 : 나는하지 않습니다 (

1) MIMETYPE의 배열 및

2 관리)

될 수있는 문자 배열을 관리 :

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()); 
+6

'std :: vector'와'std :: string'을 사용할 수없는 이유가 있을까요? – GManNickG

+0

나는 GMan과 함께하고있다. 왜이 트릭을하고 싶니? 이것이 필요한 최적화라고 측정 했습니까? – sbi

+0

웹 서버용입니다. 연결된 각 사용자에 대해 각 요청에 대해 비교해야 할 수도있는 총 646 개의 유형이 있습니다. 진짜 느려질 수 있어요. – bitwise

답변

3

나는 다른 사람이 이미 진술했기 때문에, (그냥 표준 : : 문자열, 표준 : : 벡터 등을 사용한다고하는 등)을 제외하고이 조기 최적화가 있다는 점을 넣어 것입니다.

제가 보는 근본적인 문제

당신이 MIMETYPE 구조체 그들이 가리 것이다 문자열에 동일한 메모리를 사용하고 있다는 점이다. 아무리 당신이 그것을 할당 방법, 포인터 자체와 데이터는 메모리에 정확한 같은 장소를 차지하지 수 가리키는 없습니다.


는 3 종류의 배열을 필요로하고 당신이 그들에 할당 된 메모리를 가리키는 MIMETYPE* mimeTypes했다 말할 수 있습니다.

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

extension이 설정되는 :

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

, 당신은 코드의 다음 줄에 무슨 일을하는지 고려해 포함 된 것처럼 그 메모리를 치료하고 의미

MIMETYPE 구조체 자체와 동일한 메모리 위치를 가리킬 수 있습니다. 그것은 작동하지 않을 것입니다. 후속 코드가 extension이 가리키는 위치에 쓰면 MIMETYPE 구조체를 덮어 씁니다.

마찬가지로,이 코드 :

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

는 달리 차지 MIMETYPE 구조체에 원하는 같은 메모리에 문자열 데이터를 쓰고있다.


필요한 모든 메모리를 하나의 인접한 공간에 실제로 저장하려면 이렇게하는 것이 좀 더 복잡합니다. MIMETYPE 배열을 시작 부분에 포함하도록 메모리 블록을 할당 한 다음 나중에 문자열 데이터를 할당해야합니다. 예를 들어

, 당신은 3 가지 필요하다고 할 수 있습니다. 확장 문자열 (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 

그래서, 설정을 할당하고, 정확하게 모든 채우기 당신이 뭔가하고 싶은 것 :

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

를이 경우, 메모리의 당신의 블록으로 배치 할 필요가

(참고 : 32 비트 코드의 일반적인 동작에 대한 바이트 레이아웃 설명을 기반으로합니다 .64 비트 코드는 포인터에 더 많은 공간이 사용되지만 원칙은 동일합니다. 또한 필자가 작성한 실제 코드 여기에 32/64 비트 차이와 관계없이 작동해야합니다.)

+0

예! 고맙습니다! 어떤 이유로 포인터가 메모리를 차지한다는 사실이 내 마음을 어지럽게했습니다. 나는 이것을 아직 시도하지 않았지만 나의 오류는 지금 명백하게 보인다. – bitwise

+0

지금 확인하십시오. 완벽하게 작동합니다. 다시 한 번 감사드립니다. – bitwise

5

당신은 2 할당을 혼합 당신의 목표를 정말로 이해해야합니다.) :

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

는 형태로 선형 항목을 할당하는 것이 좋습니다 것 :

new MIMETYPE[numTypes]; 
+0

내게서'+ 1' (이것은'std :: string'에 무엇이 잘못된 것인가에 대한 질문을하지만). – sbi

+1

const_ofmaxExtension은 컴파일 타임에 알려지지 않으며 메모리를 절약하려고합니다. – bitwise

+0

@cppnick - 그냥 내 표기법, 거기에 상수 표현 (변수가 아님)을 사용해야합니다. C++의 경우 ** const unsigned maxExtension = ... ** – Dewfy

0

그것을 할 \ 0로 종료하는 방법없는 문자열 ... 확장 및 유형 사이에 한 바이트를 추가합니다. 당신이 추가 \ 0을 허용 할당 여기

- OK 여기

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

당신이 확장의이 \ 0 종료에 대한 공간을 확보하지

//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); 

(문자열 렌 == maxExtension 경우) 대신 나는 그것이되어야한다고 생각한다.

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

을 선언하는 것만으로도 충분합니다. 또한 mimeTypes [i]를 오프셋으로 사용해서는 안되기 때문에 오프셋은 2 바이트 밖에 없으므로 ... 코드 위에서 사용해야하지만 액세스 위반이 발생했습니다. – bitwise

0

당신이해야 할 일은 가비지 컬렉터를 얻고 힙을 관리하는 것이다. RAII를 객체 파괴에 사용하는 단순한 수집기는 그리는 것이 어렵지 않습니다. 그렇게하면 콜렉터를 간단하게 할당 할 수 있으며 연속적으로 연결될 것임을 알 수 있습니다. 그러나이 문제가 심각한 문제인지 판단하기 전에 정말로 프로필을 작성해야합니다. 이런 일이 발생하면 string과 stringstream과 같은 많은 std 유형을 typedef하여 사용자 정의 할당자를 사용할 수 있습니다. 즉, C 스타일 문자열 공포 대신 std :: string으로 돌아갈 수 있습니다.

+0

오늘 SC2를 구입했습니다 ... LOL @ Evil 화산 행성 "Char" – bitwise

0

당신은 정말 연속 MIMETYPE의를 할당하기 위해 extensiontype의 길이를 알아야합니다 (있는 경우는 "연속"extensiontype 실제로 개체 내에 할당된다는 것을 의미한다).당신이 extensiontype의 길이가 컴파일 타임에 알 수없는 말 때문에, 당신은 배열이나 설정하고 런타임에 변경할 수있는 vectorvector (전체 길이에서이 작업을 수행 할 수는 없지만, 개별 요소의 크기를해야합니다 수 컴파일 타임에, 당신은 extensiontype)의 길이를 모른 채 그 크기를 알 수 없다.

개인적으로 vectorMIMETYPE의의를 사용하고 extensiontype 필드 모두 string의을 추천 할 것입니다. 역 참조가 느리다고 느끼는 조기 최적화와 같은 의심스러운 요구 사항입니다. 포인터가 캐시 미스를 일으키는 경우 특히 느립니다. 이 필드를 읽는 것이 실제 병목 현상이라는 실제 데이터를 얻을 때까지는 걱정하지 않아도됩니다. 그들은 특정 임계 값보다 짧은 경우는 MIMETYPE 객체 내부의 extensiontype 문자열을 할당 할 수있는 동적 그렇지 않으면이를 할당 :

그러나, 나는 가능한 "솔루션"생각할 수

#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을 죄책감을 느끼지 않고 이것을지지 할 수는 없습니다.

+1

효과적으로 구현 한 것을 _small 문자열 최적화라고합니다. 그것은 표준 라이브러리의'std :: string' class__에 이미 구현되어있을 가능성이 매우 높습니다. 버그가 없다는 것이 확실합니다. 이미 구현, 테스트 및 유용하다고 입증 된 코드를 복제하고 있습니다. __Really, 그런 최적화를하기 전에 먼저 이것이 필요한지 여부를 측정해야합니다 .__ Visage의 코멘트는이 질문에 대한 최상의 대답입니다. 코드가 깨끗하고 작동되도록 테스트 코드와 함께 작성하십시오. 그런 다음 테스트를 사용하여 프로필을 작성한 다음 최적화하여 아무런 문제가 없는지 확인하십시오. – sbi

+0

구현에 버그가 수정되었습니다. 나는 원래의 답을 쓸 때 나는 당신과 동의했다는 것을 지적하고 싶다. 그래서 나는 전체 두 번째 단락을 썼다. 그리고 그것이 제가 마지막 단락을 쓴 이유입니다. –

+0

"구현에 몇 가지 버그가 수정되었습니다." 정말로, 그렇게해서는 안됩니다. 당신이 도널드 크 누스 (Donald Knuth)가 아니라면, 이런 것들은 절대로 작동하지 않는 경향이 있습니다. 테스트되고 검증 된 구현을 사용하는 것이 훨씬 낫습니다. – sbi

관련 문제