2011-01-03 5 views
7

잘 정의 된 동작이있는 다음의 올바른 C++이 있습니까?문자 배열을 배치 용 저장소로 새로 추가

class my_class { ... }; 

int main() 
{ 
    char storage[sizeof(my_class)]; 
    new ((void *)storage) my_class(); 
} 

또는이 문제는 포인터 캐스팅/정렬 고려 사항 때문에 발생합니까?

+0

제게는 괜찮습니다. –

+2

아니요, 해당 컨텍스트에서 타원은 유효하지 않습니다 ... (힌트 : 코드가 잘 정의되어 있는지 묻고 싶다면 먼저 컴파일해야합니다.) – GManNickG

+0

위의 일을하는 용도가 무엇인지 말해주십시오. 진짜 pogramming 세계에서. – vrbilgi

답변

12

예, 문제가 있습니다. 메모리가 올바르게 정렬되었다고 보장 할 수 없습니다.

올바른 정렬로 스토리지를 얻으려면 다양한 트릭이 있지만 Boost 또는 C++ 0x의 aligned_storage을 사용하는 것이 가장 좋습니다.이 방법은 이러한 트릭을 숨 깁니다. 그런 다음

당신은 필요

// C++0x 
typedef std::aligned_storage<sizeof(my_class), 
           alignof(my_class)>::type storage_type; 

// Boost 
typedef boost::aligned_storage<sizeof(my_class), 
         boost::alignment_of<my_class>::value>::type storage_type; 

storage_type storage; // properly aligned 
new (&storage) my_class(); // okay 

참고 C++ 0X에, 속성을 사용하여, 당신은 단지이 작업을 수행 할 수있다 : 사람들이 여기에 언급했듯이

char storage [[align(my_class)]] [sizeof(my_class)]; 
+0

감사합니다. 이것은 매우 유용합니다. – bluescarni

+0

죄송합니다, 아직은 아직 없습니다 :) 내가 이해 한 한, 스토리지 유형은 일종의 내장 정수형입니다. 어떻게 사용합니까? void *를 통해 my_class 유형으로 자유롭게 캐스트 할 수 있습니까? – bluescarni

+0

죄송합니다. "my_class 인스턴스에 대한 포인터를 앞뒤로 자유롭게 던지십시오."... 또는 이와 비슷한 것 : – bluescarni

2

적어도 정렬 때문에 문제가 있습니다.

대부분의 비 인텔 아키텍처에서 정렬되지 않은 메모리 액세스를 수정하는 데 필요한 프로세서 트랩으로 인해 코드가 잘못된 정렬로 인해 "버스 오류"가 발생하거나 매우 느립니다.

인텔 아키텍처에서 이것은 보통 평소보다 조금 느립니다. 일부 SSE 작업이 관련된 경우를 제외하고는 충돌 할 수 있습니다.

0

myclass 크기의 경우 char 배열이 올바르게 정렬되지 않을 수 있습니다. 일부 아키텍처에서는 느린 액세스를 의미하고 다른 아키텍처에서는 크래시를 의미합니다. char 대신 struct의 정렬보다 크거나 같은 정렬 유형을 사용해야합니다. 정렬 유형은 해당 구성원 중 가장 큰 정렬 요구 사항에 따라 제공됩니다.

#include <stdint.h> 

class my_class { int x; }; 

int main() { 
    uint32_t storage[size]; 
    new(storage) my_class(); 
} 

my_class 예를 들어 충분한 메모리를 할당하기 위해, 나는 sizeT가 올바른 정렬을 얻기 위해 사용 중 유형 sizeof(my_class)/sizeof(T),이되어야한다고 생각합니다.

+0

"... 구조체의 정렬이 구조체의 정렬과 동일하거나 그보다 큰데, 이는 멤버 중 가장 큰 정렬 요구 사항에 의해 제공됩니다."이것이 보장되지 않는다고 생각하면 정렬은 완전히 구현에 따라 정의됩니다. (즉, 정렬은 가장 엄격한 멤버의 정렬 일 필요는 없습니다.) 또한 int는 32 비트보다 클 수 있습니다. – GManNickG

+0

@GMan : 네 말이 맞아. 그것은 대부분의 경우에 작동하지만. 여기에 링크가 있습니다 : http://stackoverflow.com/questions/364483/determining-the-alignment-of-c-c-structures-in-relation-to-its-members –

3

, 이것은하지 않습니다 반드시 정렬 제한으로 인해 작동합니다. 정렬 권리를 얻는 몇 가지 방법이 있습니다. 첫째, C++ 0x 호환 컴파일러를 사용하는 경우 alignof 연산자를 사용하여 정렬을 올바르게 수행 할 수 있습니다. 둘째로, operator new의 메모리가 무엇이든 올바르게 사용할 수 있도록 정렬되어 있기 때문에 문자 배열을 동적으로 할당 할 수 있습니다. 세 번째로, 시스템에서 가능한 최대 정렬을 갖는 어떤 타입의 문자 배열을 유니온에 저장하려고 시도 할 수 있습니다. 나는 this article이 그것에 관한 약간의 정보를 가지고 있다고 믿는다. (C++ 03을 위해 설계되었지만 곧 나오게 될 alignof 연산자만큼 좋지는 않다.)

희망이 도움이됩니다.

2

누구나 Boost 또는 C++ 1x를 피하려면 GCC와 MSVC 모두에서이 전체 코드가 작동합니다. MSVC 관련 코드는 Chromium의 aligned_memory.h을 기반으로합니다. MSVC의 __declspec(align(.))은 리터럴 정렬 값만 허용하기 때문에 GCC 버전보다 조금 복잡합니다. 이는 가능한 모든 정렬에 대해 템플릿 전문화를 사용하여 해결되었습니다.

#ifdef _MSC_VER 

template <size_t Size, size_t Align> 
struct AlignedMemory; 

#define DECLARE_ONE_ALIGNED_MEMORY(alignment) \ 
template <size_t Size> \ 
struct __declspec(align(alignment)) AlignedMemory<Size, alignment> { \ 
    char mem[Size]; \ 
}; 

DECLARE_ONE_ALIGNED_MEMORY(1) 
DECLARE_ONE_ALIGNED_MEMORY(2) 
DECLARE_ONE_ALIGNED_MEMORY(4) 
DECLARE_ONE_ALIGNED_MEMORY(8) 
DECLARE_ONE_ALIGNED_MEMORY(16) 
DECLARE_ONE_ALIGNED_MEMORY(32) 
DECLARE_ONE_ALIGNED_MEMORY(64) 
DECLARE_ONE_ALIGNED_MEMORY(128) 
DECLARE_ONE_ALIGNED_MEMORY(256) 
DECLARE_ONE_ALIGNED_MEMORY(512) 
DECLARE_ONE_ALIGNED_MEMORY(1024) 
DECLARE_ONE_ALIGNED_MEMORY(2048) 
DECLARE_ONE_ALIGNED_MEMORY(4096) 

#else 

template <size_t Size, size_t Align> 
struct AlignedMemory { 
    char mem[Size]; 
} __attribute__((aligned(Align))); 

#endif 

template <class T> 
struct AlignedMemoryFor : public AlignedMemory<sizeof(T), __alignof(T)> {};