是否明确定义在非活动联合成员上使用`std :: addressof`

时间:2018-04-11 13:08:28

标签: c++ c++11 language-lawyer

以下代码是尝试在C ++ 11中实现constexpr offsetof版本的std::addressof。它在gcc 7.2.0和clang 5.0.0中编译。

这取决于将#include <iostream> #include <cstdint> #include <memory> // based on the gist at: https://gist.github.com/graphitemaster/494f21190bb2c63c5516 // original version by graphitemaster template <typename T1, typename T2> struct offset_of_impl { union U { char c; T1 m; // instance of type of member T2 object; constexpr U() : c(0) {} // make c the active member }; static constexpr U u = {}; static constexpr std::ptrdiff_t offset(T1 T2::*member) { // The following avoids use of reinterpret_cast, so is constexpr. // The subtraction gives the correct offset because the union layout rules guarantee that all // union members have the same starting address. // On the other hand, it will break if object.*member is not aligned. // Possible problem: it uses std::addressof on non-active union members. // Please let us know at the gist if this is defined or undefined behavior. return (std::addressof(offset_of_impl<T1, T2>::u.object.*member) - std::addressof(offset_of_impl<T1, T2>::u.m)) * sizeof(T1); } }; template <typename T1, typename T2> constexpr typename offset_of_impl<T1, T2>::U offset_of_impl<T1, T2>::u; template <typename T1, typename T2> inline constexpr std::ptrdiff_t offset_of(T1 T2::*member) { return offset_of_impl<T1, T2>::offset(member); } struct S { S(int a_, int b_, int c_) : a(a_), b(b_), c(c_) {} S() = delete; int a; int b; int c; }; int main() { std::cout << offset_of(&S::b); } 应用于工会的非活跃成员。

这是定义良好的C ++ 11吗?如果没有,请解释原因,包括标准相关部分的引用或引用。

display:block

供参考,以下是可以使用的沙箱版本:https://wandbox.org/permlink/rKQXopsltQ51VtEm

以下是graphitemaster的原始版本: https://gist.github.com/graphitemaster/494f21190bb2c63c5516

1 个答案:

答案 0 :(得分:3)

union U { int a; int b; };
U u;
u.a = 0; // (1)
int* pub = &u.b;

是的,这是明确定义的,但是对pub的使用方式有限制。注意:使用运算符&std::addressof获取对象的地址与 1 类似,除非为该对象的类型定义了自定义运算符&。 / p>

  

[class.union]/1
  在联合中,如果非静态数据成员的名称引用其生命周期已开始但尚未结束的对象,则该组件处于活动状态。

因此,在标记为(1)的行上,u.b的生命周期尚未开始,但已分配了该对象占用的存储空间。以下:

  

[basic.life]/6
  在对象的生命周期开始之前但是在对象占用的存储空间已经被分配之后,或者在对象的生命周期结束之后以及在对象占用的存储被重用或释放之前,任何表示对象的地址的指针可以使用对象所在或存在的存储位置,但只能以有限的方式使用。

1)除了用户Quentin指出的那样,绑定对u.b的引用,但根据[basic.life]/7它也没关系:

  

类似地,在对象的生命周期开始之前但在对象将占用的存储之后已经分配,​​或者在对象的生命周期结束之后以及在重用或释放对象占用的存储之前,任何glvalue可以使用引用原始对象但仅限于有限的方式。对于正在建造或销毁的物体,请参阅[class.cdtor]。否则,这样的glvalue指的是已分配的存储空间([basic.stc.dynamic.allocation]),并且使用不依赖于其值的glvalue的属性是明确定义的。