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

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

<分区>

我在玩一个类,我想用 operator[] 索引它。 ,同时还能够访问这些字段。

我在下面附加了一个 MCVE,它可以通过变量本身访问成员变量,但也有一些指针偏移(例如:如果有一个 a ,和b ,然后我可以通过名称访问 b,或者如果它们是相同类型并且按顺序定位且没有填充,则通过 &a + 1 访问它)。

我担心我会遇到未定义的行为并且不知道。最初我试图做一个“与 1) float 成员和 2) float 数组的 union ”,但我发现它是 undefined behavior .如果我在下面要做的是未定义的行为,我尝试在标准中查找但找不到它(这显然并不意味着它不存在,我很容易错过它)。

因为我也在使用 CRTP 来执行此操作,所以我想既然我正在强制转换为自身,那么只要继承不提供任何成员就应该没问题。

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

  • 确保它是标准布局,这样我就可以对其他静态断言使用 offsetof 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;
}

我这样做是否违反了标准并调用了未定义的行为?当然,假设没有提供超出范围的索引。

r是第一个成员,不知道有没有6.7.2 part 4.3让我更加欣慰的是,无论我是否以安全的方式引用第一个成员。

最佳答案

您的程序的行为未定义。

指针运算仅在数组内有效。而rgb不构成数组。

最好的办法是使用包含 3 个标签的 switch block 重新编码 float& operator[](size_t)

关于c++ - 通过指向类的第一个成员的指针访问成员是否是未定义的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55225166/

相关文章:

c++ - void(int) 和 void (*)(int) 之间的区别

c++ - 计算 C++17 中 POD 类型的普通数组的字段?

c++ - 为什么 std::is_invocable 不接受非类型模板参数

c++ - 对于不确定值的无符号字符类型,左值到右值转换标准中特殊语言的意义是什么

c++ - 每个类(class)都有不同的 boost 日志接收器

c++ - boost 线程池

c++ - 在可能重叠的范围之间复制类

c++ - C++17 中的 "If constexpr"在非模板函数中不起作用

我可以通过为封闭结构分配更多空间来 "over-extend"数组吗?

c++ - 为什么 unsigned char 具有与其他数据类型不同的默认初始化行为?