Search code examples
c++memoryheap-memorynew-operatorstack-memory

Basic question about C++ memory management


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

Usially I don't care about memory, but I want to understand clearly, in what memory do cat1's and cat2's a and b exist? In stack or in heap?

@BoPerson: You're right, I should have used b = new int(0). But it's more interesting for me, where is variable a when object Cat is created in heap? a in heap, too? And pointer b in heap too and it points to memory in heap, right?


Solution

  • Let me annotate and answer in-place.

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

    As you refer to memory management in your title: Stack variables get destructed automatically when they fall out of scope. I.e. the space occupied by cat1 and cat2 (one Cat, one pointer) will be recovered when leaving main(). Also, for cat1, the destructor will be called. In your case, there is no explicit destructor but if Cat had attributes with destructors, an automatic destructor would get auto-generated.

    For pointers, the object pointed to is not automatically destructed when the pointer gets destructed. If you want that, you should have a look at smart pointers like std::auto_ptr<> (or QScopedPoiner in Qt) which gives you a pointer-like object which will indeed destruct the pointed-to object (by calling delete on it) when the auto_ptr gets destructed.

    When not employing smart pointers, you need to take care to manually destruct the pointed-to-objects using the delete operator. Take care to do it on every return-path from your current scope (multiple returns, thrown exceptions, e.g.).