course of C++ programming language

lecture 6: free store


Static members

A variable that is part of a class, yet is not part of an object of that class, is called a static data member. There is exactly one copy of a static member instead of one copy per object, as for static ordinary non-static members. Similarly, a function that needs access to members of a class, yet static doesn't need to be invoked for a particular object, is called a static member function.

class Date { int d, m, y; public: void Date (int dd, int mm, int yy); public: inline int day () { return d; } inline int month () { return m; } inline int year () { return y; } public: static const Date begining_of_the_gregorian_calendar; // the declaration static string tostring (Date dt); }; const Date Date::begining_of_the_gregorian_calendar(15,10,1582); // the definition string Date::tostring (Date dt) { /*...*/ }

A static member can be referred to like any other member. In addition, a static member can be referred to without mentioning an object. Instead, its name is qualified by the name of its class.

cout << begin.begining_of_the_gregorian_calendar.day() << endl; cout << begin.begining_of_the_gregorian_calendar.month() << endl; cout << begin.begining_of_the_gregorian_calendar.year() << endl; Date begin(Date::begining_of_the_gregorian_calendar); cout << Date::tostring(begin) << endl;

There is a single piece of storage for a static data member, regardless of how many objects of that class you create. All objects share the same static storage space for that data member, so it is a way for them to "communicate" with each other. But the static data belongs to the class; its name is scoped inside the class and it can be public, private, or protected.

Operators new and delete

You can create and destroy objects at runtime. C++ has always provided the dynamic memory allocation operators new and delete that allocate storage from the heap (also called the free store) at runtime.

double *pd = 0; pd = new double(2.72); // creating an object // ... cout << *pd << endl; // ... delete pd; // destruction of the object pointed by pd pd = 0; // ...

An object created on the free store has its constructor invoked by the new operator and exists until the delete operator is applied to a pointer to it.

class X { double x; public: X (int x=0) { this->x = x; } // the constructor ~X () { x = 0; } // the destructor public: inline double value () const { return x; } }; int main () { X *px=0, *py=0, *pz=0; px = new X; // call the default constructor X() py = new X(7); // call the ordinary constructor X(int) pz = new X(*py); // call the copy-constructor X(const X &) cout << px->get() << endl; cout << py->get() << endl; cout << pz->get() << endl; delete px; px = 0; // call the destructor ~X() delete py; py = 0; // call the destructor ~X() delete pz; pz = 0; // call the destructor ~X() }

When you create an object with new (using a new-expression), it allocates enough storage on the heap to hold the object and calls the constructor for that storage. You can create a new-expression using any constructor available for the class. If the constructor has no arguments, you write the new-expression without the constructor argument list.

// ... MyType *ptr = 0; ptr = new MyType(); // creating an object // ...

The complement to the new-expression is the delete-expression, which first calls the destructor and then releases the memory. Just as a new-expression returns a pointer to the object, a delete-expression requires the address of an object.

// ... delete ptr; // destroing of an object ptr = 0; // ...

If the pointer you're deleting is zero, nothing will happen. For this reason, people often recommend setting a pointer to zero immediately after you delete it, to prevent deleting it twice. Deleting an object more than once is definitely a bad thing to do, and will cause problems.

new and delete for arrays

In C++, you can create arrays of objects on the stack or on the heap. The constructor will be called for each object in the array. There's one constraint, however: there must be a default constructor, because a constructor with no arguments must be called for every object. There is no way to specify explicit arguments for a constructor in an array declaration.

MyType arr[100];

You can create arrays of objects on the heap using new[] operator.

MyType *arr = new MyType[100]; // ...

There is a special destruction operator for arrays, delete[].

// ... delete []arr; arr = 0;

The empty brackets tell the compiler to generate code that fetches the number of objects in the array, stored somewhere when the array is created, and calls the destructor for that many array objects.

Something about exceptions

...


References
  1. B.Stroustrup: The C++ programming language. Third edition.
    Section 10: classes; pp. 223-258.
  2. Bruce Eckel: Thinking in C++. Second edition.
    Section 4: data abstarction; pp. 217-254.
    Section 5: hiding the implementation; pp. 259-280.
    Section 6: initialization and cleanup; pp. 283-306.
    Section 8: constants; pp. 352-367.
    Section 11: references and copy-constructor; pp. 455-479.