简体   繁体   English

在c ++类中进行指针数学运算:是“合法”吗?

[英]Doing pointer math in a c++ class: Is it “legit”?

Ah-hoi, hoi, 阿海,海,

I'm wondering if it's ok to do something like the following: 我想知道是否可以执行以下操作:

class SomeClass
{
   int bar;
};

SomeClass* foo = new SomeClass();
int offset = &(foo->bar) - foo;

SomeClass* another = new SomeClass();
*(another+offset) = 3; // try to set bar to 3

Just Curious, Dan O 只是好奇Dan O

I suppose tecnically it might work out. 我想从技术上讲它可能会解决。

However, there are several problems. 但是,有几个问题。 bar is private. 酒吧是私人的。 You are mixing pointers of different types (pointer arithmetic relies on the pointer type: int* + 1 and char* + 1 have different results because int and char have a different size). 您正在混合使用不同类型的指针(指针算术依赖于指针类型:int * + 1和char * + 1的结果不同,因为int和char的大小不同)。

Have you also considered pointers to members: 您是否也考虑过指向成员的指针:

#include <cassert>

struct SomeClass
{
   int bar;
};

int main() {
    int SomeClass::*mem_ptr = &SomeClass::bar;
    SomeClass foo;
    foo.*mem_ptr = 3;
    assert(foo.bar == 3);
}

The idea is OK for POD classes (same things other people have said about the errors in your example code). POD类的想法是好的(其他人对您的示例代码中的错误说了同样的话)。 For non-POD classes, you cannot necessarily identify a member just by an offset from the object pointer. 对于非POD类,您不必仅通过与对象指针的偏移量来标识成员。 Consider for example if the member is part of a base class, or equivalently if you want to apply the offset to a pointer to a derived class, but there is multiple- or virtual inheritance involved. 例如,考虑成员是否是基类的一部分,或者等效地,如果您想将偏移量应用于派生类的指针,但是涉及多重继承或虚拟继承。

However, are you aware of pointers-to-member? 但是,您知道成员指针吗?

struct SomeClass
{
    int bar;
};

// fieldtoset is a pointer-to-member
int SomeClass::*fieldtoset = &SomeClass::bar;

SomeClass* another = new SomeClass();
// syntax works as if "*fieldtoset" is "bar" (the member variable referand)
another->*fieldtoset = 3 // set bar to 3

There's nothing wrong with it, but it's very dangerous if you're not careful. 它没有任何问题,但是如果您不小心,将非常危险。

On the other hand, your code is wrong. 另一方面,您的代码是错误的。 What's the pointer type of (another+offset)? (another + offset)的指针类型是什么? It's actually a pointer to SomeClass, not an int, so you should at least cast the pointer to (int *): 它实际上是指向SomeClass的指针,而不是int,因此您至少应将指针转换为(int *):

 *((int *)(another + offset)) = 3;

The offset is another thing to watch out for, because it's always in units of the type the pointer points to. 偏移量是另一个需要注意的问题,因为偏移量始终以指针指向的类型为单位。 In short, when int is 4 bytes long, adding 1 to a (int *) pointer will actually add 4 to it, so it's better to cast any pointer to (char *) before doing calculations. 简而言之,当int为4个字节长时,在(int *)指针上加1实际上会对其加4,因此最好在进行计算之前将任何指针转换为(char *)。

So for your example: 因此,对于您的示例:

SomeClass* foo = new SomeClass();
int offset = (char *)&(foo->bar) - (char *)foo;

SomeClass* another = new SomeClass();
*((int *)((char *)another+offset)) = 3; // try to set bar to 3

What you're doing in your example is not a good use of pointers. 您在示例中所做的并不是很好地使用指针。 It may not work if the compiler does things differently than you expect, and it can be done just as simply, just as efficiently, and with less source code, using normal methods. 如果编译器做的事情与您预期的不同,它可能无法正常工作,并且可以使用常规方法以简单,高效,较少的源代码完成它。

There's nothing wrong with pointer arithmetic if you have a valid use. 如果您有有效的使用,指针算术就没有错。 There aren't very many not already covered by the language though. 但是,该语言还没有覆盖很多。

It's okay (usually you'd define a macro for it like the Windows DDK's CONTAINING_RECORD macro), but I'd question why you'd need this in C++; 没关系(通常您会为它定义一个宏,例如Windows DDK的CONTAINING_RECORD宏),但是我想问为什么在C ++中需要它? usually you use these types of tricks in C. 通常,您在C中使用这些技巧。

Looking at the raw addresses, that seems like it would work, but for starters in your statement: int offset = &(foo->bar) - foo; 查看原始地址,这似乎可行,但对于语句中的int offset = &(foo->bar) - foo;者来说: int offset = &(foo->bar) - foo; You are trying to substract different pointer types. 您正在尝试减去不同的指针类型。 So if you reniterpret_cast them to char * it should give you what you are looking for. 因此,如果将reniterpret_cast转换为char *,它将为您提供所需的内容。

Although this seems too convoluted and error-prone to be any useful. 尽管这看起来太费解并且容易出错,但没有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM