【发布时间】:2014-07-26 08:16:19
【问题描述】:
以下代码在 G++ 中产生警告:
#include <iostream>
#include <cstdint>
template <typename T, typename P, typename Q>
Q T::*pointer_to(P T::*p, Q P::*q)
{
typedef Q T::* output_ptr;
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
size_t tmp = reinterpret_cast<const size_t&>(p) + reinterpret_cast<const size_t&>(q);
return reinterpret_cast<const output_ptr&>(tmp);
}
struct A { int x; };
struct B { A a; };
int main()
{
B b = B();
b.*pointer_to(&B::a, &A::x) = 1;
std::cout << b.a.x << std::endl;
}
无论如何它都能正常工作,但这让我担心。
您的看法是,这些“子成员”指针是否比普通成员指针更容易受到更严格的别名问题的影响?
【问题讨论】:
-
那是什么让你担心?您对编译器如何实现指向成员的指针进行了很多假设,并使用它来创建自己的指向子成员的指向成员的指针。整个事情似乎有点冒险和不可移植。你想完成什么?
-
当然我知道该方法本身可能是不可移植的,不能与虚拟基础正确互操作(尽管,转换为 size_t 应该会失败),并且是不建议使用的所有内容在 C++ 编程中 =)
-
我尝试它的原因是理论上的。指向普通(实际上是 POD)类成员的指针实际上 是 一个编译时常量偏移量。指向成员的指针可以指向给定类型的任何成员。成员类的任何成员的偏移量也具有从类开始的固定偏移量。那么想象一下,我们需要一个功能对象来修改那个深入挖掘的成员?或者,作为 C 数组的成员的一项。语言规则禁止您直接引用该成员,因此需要多个绑定。
-
无论如何,我仍然想知道,除了执行 reinterpret_cast-s 和依赖指向成员表示的 G++ 内部指针之外,这种肮脏的 hack 是否与 C++ 标准有任何额外的矛盾。好吧,你可能会说:从执行禁止的 reinterpret_cast 开始的任何事情都没有用推理。尽管如此,看起来计算值与普通成员指针有很多共同点,与它相比应该没有额外的副作用。
-
我不建议任何人练习这种 diguisting hacking,我认为我最终会坚持使用绑定的解决方案(我想它应该优化到相同的恒定积分偏移量)。尽管拥有一个指向成员成员的轻量级指针等看起来很诱人。=)
标签: c++ strict-aliasing member-pointers