C ++:指针改变了吗?

时间:2012-06-27 17:59:53

标签: c++ pointers memory-management

就在我以为自己掌握好指针时,我又感到困惑了。您的见解可能会有所帮助。

我想我可以用非常笼统的方式说明让我困惑的事情,例如:

a)如果我写A* p = new A(); (其中A是某个类),然后执行(*p).do_stuff()之类的操作,然后p指向的对象可能会在内存中移动,那么为什么p仍会指向我的对象?

b)类的类和成员变量如何存储在内存中。

但也许告诉你我有点具体的问题更有用。假设我有一个类Car,它有一个成员变量Engine engine_;(其中Engine是其他类)。精细。现在假设由于某种原因我想创建一个具有成员变量的类,该变量是指向Engine的指针,如:

class Car
{
    friend Repair;
public:
    Car() {engine_ = Engine();}
private:
    Engine engine_;
};

class Repair
{
public:
    Repair(const Car &car) : engine_(&(car.engine_)) {}
private:
    Engine *engine_;
};

repair.engine_永远不会指向我的汽车发动机,是否存在(?)但即便在第二个版本中:

class Car
{
    friend Repair;
public:
    Car() {engine_ = new Engine();}
    ~Car() {delete engine_;}
private:
    Engine *engine_;
};
// Maybe I need/should write consts somewhere, not sure

class Repair
{
public:
    Repair(const Car &car) : engine_(car.engine_) {}
private:
    Engine *engine_;
};

虽然这似乎有更多机会可行,但我不知道如何/理解它是否会......

提前感谢您的回答!

4 个答案:

答案 0 :(得分:2)

  

如果我写A* p = new A();(其中A是某个类),然后执行(*p).do_stuff()之类的操作,那么p指向的对象可能会在内存中移动

不,它不会。 (至少,*p将保持不变;如果它本身有指针成员,那么这些可能会被重置为指向别处。)

  

类的类和成员变量如何存储在内存中

作为位。

class Foo {
    int i;
    char *p;

  public:
     void bla();
};

将表示为int(可能是32)的位,后跟指针(32或64)的位,其间可能有一些填充。该方法不会占用实例中的空间,而是单独存储。

至于你的例子,我并不完全理解这个问题。只要Car对象存在,如果Engine*保持活动状态并且不重置其Repair,它就应该有效。 (但它看起来并不特别健壮。)

答案 1 :(得分:0)

在案例1)和案例2)中,无法保证repair.engine_始终指向您的汽车,因为它是朋友类而不是“Car”类的成员

答案 2 :(得分:0)

正如其他人所说,当你做像(*p).do_stuff();这样的事情时,对象不会在内存中移动。你必须误解你在某些时候学到的东西。

对于第二个问题,成员函数和成员变量存储在内存中的不同位置。成员函数的代码仅为每个类生成一次,而不是为每个类的实例生成一次。此代码存储在内存中的某个位置。

对于成员变量,这是人们在提及对象在内存中的位置时所谈论的内容。例如,如果您有类似

的类
class MyClass{
  private:
    int a;
    int b;
    double c;
  public:
    void fun();
};

我们假设它的一个实例存储在内存位置0x0000,这意味着a位于0x0000位置,b位于0x0004,而c将位于0x0008(或类似的内容取决于如何内存布局)。函数fun()完全存储在其他地方。

现在,如果我们创建MyClass的另一个实例,它的a变量可能位于0x00C,b可能位于0x0010,而c位于0x0014。最后,fun()与第一个实例的fun()位于完全相同的位置。

答案 3 :(得分:0)

使用new分配的C ++中的指针不会移动。您可能会想到malloc,其中指针可能是realloc'并且可能会因此而转到新位置。

Bjarne Stroustrup觉得C ++容器通常提供了一种更好的方法来处理动态大小的内存:

http://www2.research.att.com/~bs/bs_faq2.html#renew

为了允许内存的移动和重组,一些系统使用需要在使用它们之前锁定到指针的抽象句柄...例如Windows:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366584(v=vs.85).aspx

在需要进行某种定期内存碎片整理的系统中,使用锁定指针的抽象内容可能有意义。但是C ++默认不支付该间接的成本,只有在有意义的情况下才能实现它。

(在缺点方面,如果你分配了一百万个对象,那么使用不可移动的指针然后删除它们中的999,999个......剩下的一个对象可能会保持坐在地址空间的顶部。操作系统/分页系统应该比让这个问题更聪明,但是如果你的分配器是自定义的,这可能会使你的堆大小。例如:如果你使用内存映射文件作为支持为你的对象存储......你将被困在一个大而空的磁盘文件中。)