重载内部没有数组的[]操作符
Overloading the [] operator with no array internally
我看到了以下代码:
class SomeClass
{
public:
int mA;
int mB;
int mC;
int mD;
int operator[] (const int index) const
{
return ((int*)(this))[index];
}
};
这是如何工作的?我知道这个关键字是指向这个类的指针,但没有属性知道有多少变量…我们如何安全地访问"this"指针的[index] ?
不推荐这种类型的东西,因为它不受c++标准的保证。然而,大多数编译器确实显式地定义了它们的内存布局行为(通常基于每个体系结构),并提供#pragma
来操纵打包行为(例如MSVC中的#pragma pack
)。如果您了解/利用这些特性,您可以使它在大多数给定的编译器/体系结构上工作。然而,它将不可移植!对于每个新的编译器,您都需要重新测试和调整,这是一项代价高昂的维护任务。一般来说,我们更喜欢易于移植。
如果你真的想这样做,你可以添加一个static_assert
来验证编译器的行为。
int operator[] (const int index) const
{
static_assert(sizeof(SomeClass) == 4 * sizeof(mA), "Padding not supported");
return ((int*)(this))[index];
}
因为标准不允许对成员重新排序,所以从逻辑上我们可以推断,如果SomeClass
的大小是16,那么这段代码将按预期工作。有了assert,如果有人在不同的编译器上构建,并且它试图填充它(从而把我们搞砸了),我们至少会得到通知。
然而,我们可以符合标准并实现数组槽的名称。您可以考虑这样的模式:
class SomeClass
{
enum Index {
indexA,
indexB,
indexC,
indexD,
indexCount;
};
int mData[indexCount];
public:
int operator[] (const int index) const
{
return mData[index];
}
int& A() { return mData[indexA]; }
int& B() { return mData[indexB]; }
int& C() { return mData[indexC]; }
int& D() { return mData[indexD]; }
};
这提供了类似的功能,但由c++标准保证。
这个'工作'只是因为它是未定义的行为。编译器为mB
选择的内存位置恰好与&mA + 1
相同,mC
的地址是&mA + 2
和&mB + 1
,以此类推。
然而,类确实是"标准布局"(所有数据成员都有相同的访问说明符,并且没有使用继承[n3337§9 p7]),这在传统上确实产生了成员变量的这种组织。但这并不能保证。"标准布局"可能意味着其他东西,比如成员之间的一些填充量[n3337§9.2 p14],但我怀疑有没有任何平台真正做到了这一点。
规范确实说,在一个对象之后获取地址是合法的,所以计算&mA + 1
是合法的。[n3337§5.7 p5]规范还规定,无论指针是如何计算的,具有正确类型和值的指针都指向对象。
如果一个T类型的对象位于地址A,则一个cv T*类型的指针(其值为地址A)被称为指向该对象,而不管该值是如何获得的。[注:例如,数组末尾后1的地址(5.7)将被认为指向可能位于该地址的数组元素类型的不相关对象。]本;[n3337§3.9.2 p3]
在审查了§5.9和§5.10之后,我认为以下可能在技术上是合法的,尽管它可能有未指定的行为:
if (&mA + 1 == &mB && &mB + 1 == &mC && &mC + 1 == &mD) {
return ((int*)(this))[index];
}
即使强制转换也是合法的,因为规范中说标准布局类可以强制转换为指向其第一个成员的指针。[n3337§9.2 p20]
- 矩阵上的数组下标操作符
- 使用PoDoFo-lib从PDF操作符中的数组TJ中提取文本
- 涉及数组指针时delete[]操作符的问题
- 在使用c++类的下标操作符传递的数组中使用关系操作符
- 指针、数组和新的操作符
- 使用自增操作符添加数组元素
- 如何重载下标操作符以允许RPG字符数组
- 用指针数组重载输入操作符
- c++为什么不使用星号操作符访问动态数组
- 重载数组下标操作符
- 内存管理:使用new操作符进行数组和动态分配
- 用模板和指针重载数组操作符
- 如何正确解引用没有[]操作符的多维数组
- 在2D数组中通过重载数组下标操作符进行访问
- 重载2D数组操作符并抛出异常
- 动态数组和操作符重载会导致内存崩溃
- c++静态数组和sizeof操作符
- 动态数组释放(赋值操作符与复制构造函数)
- 泛型数组的重载[]和=操作符
- 类内动态数组的复制构造函数和操作符=