关于C ++内存管理的基本问题

时间:2011-02-26 11:32:39

标签: c++ memory stack heap new-operator

// 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;
}

通常我不关心记忆,但我想清楚地理解,cat1cat2的{​​{1}}和a存在于什么记忆中?在堆栈中还是在堆中?

@BoPerson:你是对的,我应该使用b。但对我来说这更有意思,当在堆中创建对象b = new int(0)时,变量a在哪里?堆中也Cat?并且指针a也在堆中,它指向堆中的内存,对吧?

3 个答案:

答案 0 :(得分:7)

让我注释并就地回答。

class Cat()
{
public:
     Cat()
     {
          a = 0; // ok: sets the variable a, wherever it lives
          (*b) = 0; // not ok: stores an integer 0 to wherever b points
                    // since b was never initialized to anything, it can write
                    // anywhere you can imagine. If you are lucky, your compiler
                    // implicitly initializes the pointer to zero such that you
                    // at least get a deterministic segmentation violation.
     }

     int a; // an integer variable living wherever Cat gets constructed
     int* b; // a pointer variable living wherever Cat gets constructed pointing 
             // to wherever it gets set to (b = something) could be heap, stack, 
             // mapped memory, out-of-control (like here)
};

int main(int argc, char* argv[])
{
     Cat cat1; // allocates cat1 on the stack, all attributes (a and b) live 
               // there. Where cat1.b points to is unrestricted.
     Cat* cat2 = new Cat(); // allocates an object of class Cat on heap, 
               // allocates a pointer variable cat2 on the stack and stores the 
               // pointer to said heap-allocated Cat in it
               // again, where cat2.b points to is unrestricted.
     return 0; // maybe never reached due to segfault ;-)
}

当您在标题中引用内存管理时:堆栈变量在超出范围时会自动被破坏。即离开main()时,cat1cat2占用的空间(一个Cat,一个指针)将被恢复。此外,对于cat1,将调用析构函数。在您的情况下,没有明确的析构函数,但如果Cat具有析构函数的属性,则会自动生成自动析构函数。

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

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

答案 1 :(得分:4)

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

Cat cat1; //stack

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

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

堆上的内存也可以删除。使用'delete'命令。这使您的程序运行更高效。

我是否遗漏了任何关键指针?

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

答案 2 :(得分:1)

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

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

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

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

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