微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c – 为什么抛出指向原始类的指针的奇怪行为?

假设在我的代码中我必须将void *存储为数据成员,并在需要时将其强制转换回原始类指针.为了测试它的可靠性,我写了一个测试程序( linux ubuntu 4.4.1 g -04-Wall),我很震惊地看到了这个行为.
struct A
{
  int i;
  static int c;
  A () : i(c++) { cout<<"A() : i("<<i<<")\n"; }
};
int A::c;

int main ()
{
  void *p = new A[3];  // good behavior for A* p = new A[3];
  cout<<"p->i = "<<((A*)p)->i<<endl;
  ((A*&)p)++;
  cout<<"p->i = "<<((A*)p)->i<<endl;
  ((A*&)p)++;
  cout<<"p->i = "<<((A*)p)->i<<endl;
}

这只是一个测试程序;实际上,对于我的情况,必须将任何指针存储为void *,然后将其强制转换回实际指针(借助模板).所以我们不要担心这一部分. output of the above code是,

p->i = 0
p->i = 0 // ?? why not 1
p->i = 1

但是如果你改变了void * p;到A * p;它给了expected behavior.为什么?

一个问题,我无法逃避(A *&),否则我不能使用操作符;但它也发出了警告,dereferencing type-punned pointer will break strict-aliasing rules.有没有可行的方法来克服警告?

解决方法

好吧,正如编译器警告你的那样,你违反了严格的别名规则,这正式意味着结果是未定义的.

您可以通过使用增量的函数模板来消除严格的别名冲突:

template<typename T>
void advance_pointer_as(void*& p,int n = 1) {
    T* p_a(static_cast<T*>(p));
    p_a += n;
    p = p_a;
}

使用此函数模板,main()的以下定义会在Ideone编译器上生成预期结果(并且不发出警告):

int main()
{
    void* p = new A[3];
    std::cout << "p->i = " << static_cast<A*>(p)->i << std::endl;
    advance_pointer_as<A>(p);
    std::cout << "p->i = " << static_cast<A*>(p)->i << std::endl;
    advance_pointer_as<A>(p);
    std::cout << "p->i = " << static_cast<A*>(p)->i << std::endl;
}

原文地址:https://www.jb51.cc/c/117081.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐