8

我有一个由违反严格的指针别名规则引起的问题。我有一个T来自模板的类型和一些Int相同大小的整数类型(如sizeof)。我的代码基本上执行以下操作:

T x = some_other_t;
if (*reinterpret_cast <Int*> (&x) == 0)
  ...

因为T是一些可以具有构造函数的任意(除了大小限制)类型,所以我不能将Tand合并Int。(这仅在 C++0x 中允许,甚至 GCC 还不支持)。

有什么办法可以重写上述伪代码以保留功能并避免破坏严格的别名规则?请注意,这是一个模板,我无法控制T; some_other_t赋值和随后的比较确实发生在模板代码中。

T(作为记录,如果包含任何位字段,上述代码在 GCC 4.5 上开始中断。)

4

5 回答 5

1
static inline int is_T_0(const T *ob)
{
        int p;
        memcpy(&p, ob, sizeof(int));
        return p == 0;
}

void myfunc(void)
{
    T x = some_other_t;
    if (is_T_0(&x))
        ...

在我的系统上,GCC 优化了is_T_0()memcpy(),导致myfunc().

于 2010-06-05T21:44:53.083 回答
1

使用 33 位计算机。;-P

于 2010-06-05T18:12:05.523 回答
1

你听说过boost::optional吗?

我必须承认我不清楚这里的真正问题......但是 boost::optional 允许按值存储,但知道实际内存是否已初始化。我也允许就地建造和破坏,所以我猜这可能是一个很好的选择。

编辑

我想我终于抓住了这个问题:您希望能够在内存中的各个点分配大量对象,并且您想知道此时的内存是否真的保存了一个对象。

不幸的是,您的解决方案有一个大问题:它不正确。如果T可以以某种方式用null位模式表示,那么您会认为它是未初始化的内存。

您将不得不自己添加至少一点信息。真的不多,毕竟这只是增长的 3%(4 个字节 33 位)。

例如,您可以使用一些模仿boost::optional但以数组方式(以避免填充损失)。

template <class T, size_t N>
class OptionalArray
{
public:


private:
  typedef unsigned char byte;

  byte mIndex[N/8+1];
  byte mData[sizeof(T)*N]; // note: alignment not considered
};

然后就这么简单:

template <class T, size_t N>
bool OptionalArray<T,N>::null(size_t const i) const
{
  return mIndex[i/8] & (1 << (i%8));
}

template <class T, size_t N>
T& OptionalArray<T,N>::operator[](size_t const i)
{
  assert(!this->null(i));
  return *reinterpret_cast<T*>(mData[sizeof(T)*i]);
}

注意:为简单起见,我没有考虑对齐问题。如果您不了解该主题,请在摆弄内存之前先阅读一下:)

于 2010-06-05T16:30:37.807 回答
1

为什么不简单:

const Int zero = 0;
if (memcmp(&some_other_t, &zero, sizeof(zero)) == 0)
  /* some_other_t is 0 */

(您可能还想尝试添加static限定符以zero查看它是否在性能方面有所不同)

于 2012-07-15T07:14:24.560 回答
0

这个怎么样:

Int zero = 0;
T x = some_other_t;
if (std::memcmp(&x, &zero, sizeof(zero)) == 0)

它可能效率不高,但它应该摆脱警告。


附录#1:

由于T被限制为与 相同的大小Int,因此将自己设为类型的虚拟按位零值T并直接与它进行比较(而不是强制转换和比较 agaist Int(0))。

如果你的程序是单线程的,你可以有这样的东西:

template <typename T>
class Container
{
public:
    void foo(T val)
    {
        if (zero_ == val)
        {
            // Do something
        }
    }

private:
    struct Zero
    {
        Zero() {memset(&val, 0, sizeof(val));}
        bool operator==(const T& rhs) const {return val == rhs;}
        T val;
    };
    static Zero zero_;
};

如果它是多线程的,您将希望避免使用静态成员zero_,并让每个容器实例都拥有自己的zero_成员:

template <typename T>
class MTContainer
{
public:
    MTContainer() {memset(zero_, 0, sizeof(zero_));}

    void foo(T val)
    {
        if (val == zero_)
        {
            // Do something
        }
    }

private:
    T zero_;
};

附录#2:

让我把上面的附录换成另一种更简单的方式:

// zero is a member variable and is inialized in the container's constructor
T zero;
std::memset(&zero, 0, sizeof(zero));

T x = some_other_t;
if (x == zero)
于 2010-06-05T15:48:46.350 回答