严格的指针别名:针对特定问题的任何解决方案?

发布于 2024-09-04 18:46:20 字数 557 浏览 13 评论 0原文

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

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

因为 T 是可以具有构造函数的任意(大小限制除外)类型,所以我无法将 T结合起来>int。 (这仅在 C++0x 中允许,甚至 GCC 还不支持)。

有什么方法可以重写上面的伪代码以保留功能并避免违反严格的别名规则?请注意,这是一个模板,我无法控制 Tsome_other_t 的值;赋值和随后的比较确实发生在模板化代码内。

(郑重声明,如果 T 包含任何位字段,则上述代码在 GCC 4.5 上开始损坏。)

I have a problem caused by breaking strict pointer aliasing rule. I have a type T that comes from a template and some integral type Int of the same size (as with sizeof). My code essentially does the following:

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

Because T is some arbitary (other than the size restriction) type that could have a constructor, I cannot make a union of T and Int. (This is allowed only in C++0x only and isn't even supported by GCC yet).

Is there any way I could rewrite the above pseudocode to preserve functionality and avoid breaking strict aliasing rule? Note that this is a template, I cannot control T or value of some_other_t; the assignment and subsequent comparison do happen inside the templated code.

(For the record, the above code started breaking on GCC 4.5 if T contains any bit fields.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

冷夜 2024-09-11 18:46:20
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() 中只生成了一些汇编指令。

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))
        ...

On my system, GCC optimizes away both is_T_0() and memcpy(), resulting in just a few assembly instructions in myfunc().

掩于岁月 2024-09-11 18:46:20

您听说过 boost::Optional 吗?

我必须承认我不清楚这里的真正问题......但是 boost::Optional 允许按值存储,但知道实际内存是否已初始化。我还允许就地构建和销毁,所以我想这可能是一个不错的选择。

编辑

我想我终于抓住了这个问题:你希望能够在内存中的不同点分配很多对象,并且你想知道此时的内存是否已分配是否真的持有一个物体。

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

您将不得不自己添加至少一点信息。实际上并不算多,毕竟只增长了 3%(33 位对应 4 个字节)。

例如,您可以使用一些模仿 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]);
}

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

Have you heard about boost::optional ?

I must admit I am unclear as to the real problem here... but boost::optional allow to store by value and yet know whether or not the actual memory has been initialized. I also allows in place construction and destruction, so could be a good fit I guess.

EDIT:

I think I finally grasped the problem: you want to be able to allocate a lot of objects, at various points in memory, and you'd like to know whether or not the memory at this point really holds an object or not.

Unfortunately your solution has a huge issue: it's incorrect. If ever T can somehow be represented by a null bit pattern, then you'll think it's unitialized memory.

You will have to resort yourself to add at least one bit of information. It's not much really, after all that's only 3% of growth (33 bits for 4 bytes).

You could for example use some mimick boost::optional but in an array fashion (to avoid the padding loss).

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

Then it's as simple as that:

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

note: For simplicity's sake I have not considered the issue of alignment. If you don't know about the subject, read about it before fiddling with memory :)

和影子一齐双人舞 2024-09-11 18:46:20

使用 33 位计算机。 ;-P

Use a 33-bit computer. ;-P

痕至 2024-09-11 18:46:20

为什么不简单地:(

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

您可能想尝试将 static 限定符添加到 zero 以查看它是否会在性能方面产生差异)

Why not simply:

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

(you may want to try to add also the static qualifier to zero to see if it makes a difference performance-wise)

怎么样:

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

它可能没有那么有效,但它应该消除警告。


附录 #1:

由于 T 被限制为与 Int 相同的大小,因此将自己设置为 T 类型的虚拟按位零值并直接比较反对它(而不是与 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_,并让每个容器实例拥有它自己的< code>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)

How about this:

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

It might not be as efficient, but it should get rid of the warning.


ADDENDUM #1:

Since T is constrained to be the same size as Int, make yourself a dummy bitwise zero value of type T and compare directly against it (instead of casting and comparing agaist Int(0)).

If your program is single-threaded, you could have something like this:

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_;
};

If it is multi-threaded, you'll want to avoid using a static member zero_, and have each container instance hold it's own zero_ member:

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

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

private:
    T zero_;
};

ADDENDUM #2:

Let me put the above addendum in another, simpler way:

// 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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文