指向数据成员的指针是如何分配/存储在内存中的?

时间:2012-09-05 15:19:41

标签: c++ class memory-management

这是一个对我没有意义的话题。可以声明和使用指向类的数据成员的指针。然而,

  1. 支持这个想法的逻辑是什么? [我不是在谈论语法,而是这个功能的逻辑]

  2. 此外,如果我理解正确,这意味着在指针初始化时分配了无限/可变量的内存,因为此时可能存在任意数量的对象。此外,可以在运行时期间创建和销毁新对象。因此,实际上,单个语句将导致大量分配/解除分配。与其他语言相比,这似乎是违反直觉的。或者我对此的理解不正确?我不认为有任何其他单一的初始化语句会像这样广泛地隐含地影响程序执行。

  3. 最后,如何将内存分配给这些指针?它们放置在物体的哪个位置?是否可以查看这些指针的物理内存地址?

3 个答案:

答案 0 :(得分:3)

  

指向数据成员的指针的单个声明,为该类的每个对象创建指针。

不,它没有。指向成员的指针是一个与指针非常不同的特殊对象;它与偏移量更相似。给定指向类的对象和成员指针的指针,您将能够获得成员的值;没有指向类对象的指针,指向成员的指针是无用的。

问题2和问题3源于同样的基本误解。

答案 1 :(得分:2)

  

指向数据成员的指针的单个声明,为该类的每个对象创建指针。

没有。它创建了一个指向成员的指针(尽管可以作为对象基础的偏移量) 然后,您可以使用指向对象的指针来获取该成员。

struct S
{
    int  x;
    int  y;
};

int S::*  ptrToMember = &S::x;  // Pointer to a member.

S   obj;
int*      ptrToData   = &obj.x; // Pointer to object
                                // that happens to be a member

请注意,在创建指向成员的指针时,我们不使用对象(我们只使用类型信息)。因此,此指针是类的偏移量,以获取特定成员。

您可以通过指针或对象访问数据成员。

(obj.*ptrToMember)   = 5;   // Assign via pointer to member (requires an object)
*ptrToData           = 6;   // Assign via pointer already points at object.
  

为什么会发生这种情况而不是创建一个指针只指向该类的一个特定实例?

这被称为指针 一个类似但平行的概念(见上文)。

  

支持这个想法的逻辑是什么?

愚蠢的例子:

 void addOneToMember(S& obj, int S::* member) { (obj.*member) += 1; }

 void addOneToX(S& obj)    { addOneToMember(obj, &Obj::x);}
 void addOneToY(S& obj)    { addOneToMember(obj, &Obj::y);}
  

另外,如果我理解这一点,这意味着在指针初始化时分配了无限/可变量的内存,因为当时可能存在任意数量的对象。

没有。因为指向成员的指针只是对象的偏移量。您仍然需要实际对象来获取值。

  

最后,如何将内存分配给这些指针?

与其他对象相同。在布局方面没有什么特别之处 但实际布局是实现定义的。因此,如果不参考编译器,就无法回答这个问题。但这对你没用。

  

是否可以查看这些指针的物理内存地址?

不确定。它们就像其他物体一样。

 // Not that this will provide anything meaningful.
 std::cout.write(reinterpret_cast<char*>(&ptrToMember), sizeof(ptrToMember));

 // 1) take the address of the pointer to member.
 // 2) cast to char* as required by write.
 // 3) pass the size of the pointer to member 

 // and you should write the values printed out.
 // Note the values may be non printable but I am sure you can work with that
 // Also note the meaning is not useful to you as it is compiler dependent.

答案 2 :(得分:0)

在内部,对于没有虚拟基础的类,指向成员数据的指针只需要保持数据成员从该类型对象的开头的偏移量。对于虚拟基础,它有点复杂,因为虚拟基础的位置可能会发生变化,具体取决于最派生对象的类型。无论如何,都涉及少量数据,当您取消引用指向数据的成员时,编译器会生成适当的代码来访问它。