就在我以为自己掌握好指针时,我又感到困惑了。您的见解可能会有所帮助。
我想我可以用非常笼统的方式说明让我困惑的事情,例如:
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_;
};
虽然这似乎有更多机会可行,但我不知道如何/理解它是否会......
提前感谢您的回答!
答案 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个......剩下的一个对象可能会保持坐在地址空间的顶部。操作系统/分页系统应该比让这个问题更聪明,但是如果你的分配器是自定义的,这可能会使你的堆大小。例如:如果你使用内存映射文件作为支持为你的对象存储......你将被困在一个大而空的磁盘文件中。)