1
// main.cpp

class Cat()
{
public:
     Cat()
     {
          a = 0;
          (*b) = 0;
     }

     int a;
     int* b;
};

int main(int argc, char* argv[])
{
     Cat cat1;
     Cat* cat2 = new Cat();
     return 0;
}

通常我不关心内存,但我想清楚地了解,在什么内存中cat1' 和'cat2存在?在堆栈中还是在堆中?ab

@BoPerson:你说得对,我应该使用b = new int(0). 但对我来说更有趣的是,在堆中创建a对象时变量在哪里?在堆中,也是?还有堆中的指针,它指向堆中的内存,对吗?Catab

4

3 回答 3

8

让我就地注释和回答。

类猫()
{
上市:
     猫()
     {
          a = 0; // ok: 设置变量 a,不管它在哪里
          (*b) = 0; // 不正确:将整数 0 存储到 b 指向的任何位置
                    // 因为 b 从未被初始化为任何东西,它可以写
                    // 你能想象到的任何地方。如果你幸运的话,你的编译器
                    // 隐式地将指针初始化为零,这样你
                    // 至少得到一个确定性的分段违规。
     }

     诠释一个; // 一个整数变量存在于 Cat 被构造的任何地方
     诠释* b; // 一个指针变量,无论 Cat 被构造指向哪里
             // 设置为 (b = something) 的任何位置都可以是堆、堆栈、
             // 映射内存,失控(就像这里)
};

int main(int argc, char* argv[])
{
     猫猫1;// 在堆栈上分配 cat1,所有属性(a 和 b)都有效
               // 那里。cat1.b 指向的位置不受限制。
     猫* cat2 = 新猫();// 在堆上分配一个 Cat 类的对象,
               // 在栈上分配一个指针变量 cat2 并存储
               // 指向其中的堆分配 Cat 的指针
               // 同样,cat2.b 指向的地方是不受限制的。
     返回0;// 可能由于段错误而永远无法到达 ;-)
}

正如您在标题中提到的内存管理:堆栈变量超出范围时会自动销毁。cat1即和(一只猫,一只指针)占用的空间cat2在离开main()时会被回收。此外,对于 cat1,将调用析构函数。在您的情况下,没有显式析构函数,但如果 Cat 具有带有析构函数的属性,则会自动生成自动析构函数。

对于指针,当指针被破坏时,指向的对象不会自动破坏。如果你愿意,你应该看看像 std::auto_ptr<> (或 Qt 中的 QScopedPoiner )这样的智能指针,它为你提供了一个类似指针的对象,它确实会破坏指向的对象(通过调用 delete )当 auto_ptr 被破坏时。

当不使用智能指针时,您需要注意使用删除运算符手动破坏指向的对象。请注意在当前范围内的每个返回路径上执行此操作(例如多次返回、抛出的异常)。

于 2011-02-26T12:18:47.747 回答
4

new 关键字将您的对象分配给堆。虽然您的第一个示例为堆栈分配了内存。

Cat cat1; //stack

Cat* cat2 = new Cat(); //heap

堆栈内存不像堆内存那样容易获得。基本上,您将内存与 new 一起存储在堆上,并将该地址存储在指针中。

堆上的内存也可以删除。使用“删除”命令。这使您的程序更有效地运行。

我错过了任何关键指针吗?

编辑:堆上的内存在不再使用时应该被删除,不仅仅是为了效率,而是为了避免程序膨胀。(内存泄漏) - 谢谢@Felice Pollano

于 2011-02-26T11:35:40.413 回答
1

cat1 在堆栈上分配。该类为 8 个字节(如果您的平台上的整数和指针为 4 个字节)。前 4 个字节是整数 a。第二个 4 字节是整数 b。

cat2 在堆内存中分配。否则与上面完全相同。

堆栈变量是“作用域的”。这意味着当堆栈帧被弹出(即退出函数)时,它会被释放并调用它的解构函数。

另一方面,堆变量将一直存在,直到您“删除”内存。

另请注意,您的构造格式不正确。"*b" 取消引用指针(即获取指针所指向的数据)。然后分配 0。出现的问题是 b 不指向任何确定的内存,因此您将 0 写入可能不在进程地址空间中的未知内存位置。我会以为你的意思是“b = NULL;”

于 2011-02-26T11:41:13.757 回答