잘 훈련 된 땅에서 어리석은 첫 게시물 일지 미리 사과드립니다. 주제에 대해 많은 자료가 있지만, 그 중 거의 확실하지 않으며 나에게 알기 쉽습니다.C++ : 엄격한 앨리어싱 대 노조의 학대
임의로 정렬 된 힙에 동적으로 메모리를 할당하는 템플릿 클래스가 있습니다 (AVX 어셈블리 루틴의 경우 32 바이트 정렬 필요). 이렇게하려면 추한 포인터 조작이 필요합니다.
Agner Fog는 cppexamples.zip에서 union을 악용하여 (http://www.agner.org/optimize/optimization_manuals.zip) 샘플 클래스를 제공합니다. 그러나 저는 한 노조원에게 글을 쓰고 다른 한권제에서 읽으면 UB가된다는 것을 압니다.
AFAICT 모든 포인터 유형을 char *
으로 별명을 지정하는 것이 안전하지만 한 방향으로 만 지정하는 것이 안전합니다. 이것은 나의 이해가 퍼지게되는 곳이다.
template <typename T, size_t alignment = 32>
class AlignedArray
{
size_t m_size;
char * m_unaligned;
T * m_aligned;
public:
AlignedArray (size_t const size)
: m_size(0)
, m_unaligned(0)
, m_aligned(0)
{
this->size(size);
}
~AlignedArray()
{
this->size(0);
}
T const & operator [] (size_t const i) const { return m_aligned[i]; }
T & operator [] (size_t const i) { return m_aligned[i]; }
size_t const size() { return m_size; }
void size (size_t const size)
{
if (size > 0)
{
if (size != m_size)
{
char * unaligned = 0;
unaligned = new char [size * sizeof(T) + alignment - 1];
if (unaligned)
{
// Agner:
/*
union {
char * c;
T * t;
size_t s;
} aligned;
aligned.c = unaligned + alignment - 1;
aligned.s &= ~(alignment - 1);
*/
// Me:
T * aligned = reinterpret_cast<T *>((reinterpret_cast<size_t>(unaligned) + alignment - 1) & ~(alignment - 1));
if (m_unaligned)
{
// Agner:
//memcpy(aligned.c, m_aligned, std::min(size, m_size));
// Me:
memcpy(aligned, m_aligned, std::min(size, m_size));
delete [] m_unaligned;
}
m_size = size;
m_unaligned = unaligned;
// Agner:
//m_aligned = aligned.t;
// Me:
m_aligned = aligned;
}
return;
}
return;
}
if (m_unaligned)
{
delete [] m_unaligned;
m_size = 0;
m_unaligned = 0;
m_aligned = 0;
}
}
};
그래서 방법은 안전 (R) : 여기 내 AlignedArray
클래스의 축소 된 버전 (Agner의 본질적 재 작성, 내 이해를 돕기 위해이)입니까?
대신'운영자 new'에서 T로, 당신은 왜 (원시 메모리를 잡아하지 않는 것이 주조 후'char' 개체를 구성하고 다음은
은 고정 것을 제안하여 기능의 버전입니다 , 또는 심지어'malloc')을'void *'로 정의하고 실제로'T' 객체를 구성합니까? 기본적으로 T 객체를 원하면 T 객체를 만듭니다. 이 유스 케이스 (정렬 된 배열)는 앨리어스 트릭/유니온/memcpy/무엇이든 * 제로 * 필요합니다. –@ R.MartinhoFernandes : 예외적으로, 수학은'void *'에 허용되지 않습니다. 정렬 된'void * '를 어떻게 얻습니까? – Omnifarious
@Omnifarious 마지막으로 확인했는데 수학은'char * '에도 허용되지 않습니다. (그렇다고해도 char 객체를 생성하고 T 객체를 생성 할 필요가 없다는 의미는 아닙니다.) 수학을 수행하려면 정수가 필요합니다. C++ 11의 이식 가능한 솔루션은 http://en.cppreference.com/w/cpp/memory/align입니다. 이론적으로는 이식 가능하지 않은 솔루션은 숫자 형식으로 reinterpret_cast를 수행하고 수학을 수행 한 다음 reinterpret_cast를 다시 수행하는 것입니다. (모든 구현에서 숫자 형에 대한 reinterpret_cast가 예상대로 작동하기 때문에 실제로는 꽤 휴대 가능합니다.) –