通过指向类的第一个成员的指针访问成员是否是未定义的行为

时间:2019-03-18 15:48:18

标签: c++ c++17 undefined-behavior

我正在玩一个我想用function username_exists($value){ global $db; $query = "SELECT * FROM users WHERE username=" . $value; $result = mysqli_query($db, $query); return mysqli_num_rows($result)>0? 'true' : 'false'; } 对其进行索引的类,同时还能够访问这些字段。

我在要执行的操作下面附加了一个MCVE,它可以通过变量本身访问成员变量,但也可以使用一些指针偏移量(例如:如果有operator[] ,和a,然后我就可以按名称访问b了,如果它们是相同类型并且按顺序放置而没有填充,则可以通过b访问它。

我担心我会遇到不确定的行为,并且不会知道。最初,我试图做一个“具有1个成员(成员)和2个成员(数组)的联合”,但是我发现它是undefined behavior。我尝试在标准中查找是否要在下面执行的操作是未定义的行为,但无法找到它(这显然并不意味着它不存在,我很可能会错过它)。

由于我也使用CRTP来执行此操作,因此我认为,自言自语,只要继承不提供任何成员,就应该可以。

为了确保这在C ++中可能是合法的,我添加了一堆静态断言,其中:

  • 确保它是标准布局,所以我可以将offsetof用于其他静态断言&a + 1
  • 确保它不重要static_assert(std::is_standard_layout_v<Color>);
  • 确保偏移量是连续的static_assert(std::is_trivial_v<Color>);static_assert(offsetof(Color, r) == 0);static_assert(offsetof(Color, g) == sizeof(float));
  • 确保从继承static_assert(offsetof(Color, b) == 2 * sizeof(float));到类中没有添加任何东西

代码:

static_assert(sizeof(Color) == 3 * sizeof(float));

我是否违反标准并通过执行上述操作调用未定义的行为?假设当然没有提供超出范围的索引。

由于#include <iostream> using namespace std; template <typename T> class ColorCRTP { T& getInstance() { return *static_cast<T*>(this); } public: // Is it UB to do this when we set values from the // fields themselves in the actual class? float& operator[](size_t index) { // Assume the inheriting class *always* is only a // series of sequential members of the exact same // type. return *(&getInstance().r + index); } }; struct Color : ColorCRTP<Color> { float r; float g; float b; Color() = default; Color(float r, float g, float b) : r(r), g(g), b(b) { } }; // Do these help guarantee that I am not performing UB? static_assert(std::is_standard_layout_v<Color>); static_assert(std::is_trivial_v<Color>); static_assert(offsetof(Color, r) == 0); static_assert(offsetof(Color, g) == sizeof(float)); static_assert(offsetof(Color, b) == 2 * sizeof(float)); static_assert(sizeof(Color) == 3 * sizeof(float)); int main() { Color c{0.5f, 0.75f, 1.0f}; c.g = 0.123f; cout << c[1] << " = " << c.g << endl; c[1] = 0.321f; // This is legal or UB? cout << c[1] << " = " << c.g << endl; } 是第一个成员,所以我不知道6.7.2 part 4.3是否以一种安全的方式引用了第一个成员,这给我带来了更多安慰。

1 个答案:

答案 0 :(得分:1)

程序的行为是不确定的。

指针算术仅在数组内有效。并且gbfloat& operator[](size_t)不会形成数组。

您最好的选择是用包含3个标签的switch块重新编码FULL OUTER JOIN