指针和数据之间的联盟,可能存在陷阱?

时间:2011-09-21 21:53:57

标签: c++ algorithm types

我正在编写一个系统,该系统具有大量需要保留在内存中的冗余数据,并且可以在尽可能小的延迟下访问。 (未压缩,数据保证吸收1GB内存,最低)。

我想到的一种方法是创建一个如下容器类:

class Chunk{
    public:
        Chunk(){ ... };
        ~Chunk() { /*carefully delete elements according to mask*/ };
        getElement(int index);
        setElement(int index);

    private:
        unsigned char mask;  // on bit == data is not-redundant, array is 8x8, 64 elements
        union{
            Uint32 redundant;  // all 8 elements are this value if mask bit == 0 
            Uint32 * ptr;      // pointer to 8 allocated elements if mask bit == 1
        }array[8];
};

我的问题是,使用联盟在Uint32主要指针和Uint32*指针之间切换是否有任何看不见的后果?

2 个答案:

答案 0 :(得分:3)

这种方法对所有C ++实现都应该是安全的。

但请注意,如果您了解平台的内存对齐要求,则可能比此更好。特别是,如果您知道内存分配对齐到2个字节或更多(许多平台使用8或16个字节),您可以使用指针的低位作为标志:

class Chunk {
 //...
  uintptr_t ptr;
};

// In your get function:    
if ( (ptr & 1) == 0 ) {
  return ((uint32_t *)ptr)[index];
} else {
  return *((uint32_t *)(ptr & ~(uintptr_t)0);
}

您可以通过使用自定义分配方法(使用placement new)进一步减少空间使用量,并将指针放在类之后,在单个内存分配中(即,您将为Chunk分配空间,并且掩码或数组,ptr之后立即指向Chunk。或者,如果您知道大多数数据的位数较低,则可以直接使用ptr字段作为填充值:

} else {
  return ptr & ~(uintptr_t)0;
}

如果它是通常未使用的高位,则会有一点位移位:

} else {
  return ptr >> 1;
}

请注意tagging pointers的这种方法是不可移植的。只有在可以确保内存分配正确对齐的情况下才是安全的。在大多数桌面操作系统上,这不会是一个问题 - malloc已经确保了一定程度的对齐;在Unix上,使用posix_memalign可以绝对肯定。但是,如果您可以为您的平台获得这样的保证,这种方法可能非常有效。

答案 1 :(得分:2)

如果空间有限,你可能会浪费记忆力。它将为最大元素分配足够的空间,在这种情况下,指针最多可以是64位。

如果坚持使用32位体系结构,则不应该遇到强制转换问题。