C++ For Science and Engineering Lecture 32

John Chrispell

Tulane University

Monday November 15, 2010 Dynamic Memory and Classes

We need to address using the new operator inside a class constructor. This brings up some questions: How do we write the class constructor? How do we update the class destructor to deal with the use of new? How will dynamic memory effect how we use and create a ++ class?

John Chrispell, Monday November 15, 2010 slide 3/25 Dynamic Memory and Classes

Lets remember what new does for us. It allows us to delay making memory decisions untill we come across an instance where we need to assign some memory. This is nice as we don’t have to preallocate all the programs memory. It is also nice as we are not allocating more memory than we need. If you remember from previous notes. We dynamically assign memory in C++ using new. This put the deallocation of freeing of this memory in our hands and we needed to have a corresponding call to the delete operator. This means that class destroctors become needed and not just ornamental.

John Chrispell, Monday November 15, 2010 slide 5/25 The StringBad Class

To gain insight into how new and delete work for classes we will use the StringBad and later the String class. Note these classes are academic versions of the standard string class. // s t n g b a d . h −− f l a w e d s t r i n g c l a s s d e f i n i t i o n #include #i f n d e f STRNGBAD H #define STRNGBAD H c l a s s StringBad { p r i v a t e : char ∗ s t r ; // p o i n t e r to s t r i n g i n t l e n ; // l e n g t h o f s t r i n g s t a t i c i n t n u m s t r i n g s ; // number o f o b j e c t s

p u b l i c : StringBad ( const char ∗ s ) ; // constructor StringBad (); // d e f a u l t constructor ˜StringBad (); // d e s t r u c t o r // f r i e n d f u n c t i o n f r i e n d std::ostream & operator <<(std::ostream & os, const StringBad & st); } ; #en dif

John Chrispell, Monday November 15, 2010 slide 7/25 The StringBad Class

We should note two things about this class declaration. It uses a pointer-to-char instead of a char array to represent a name. This means it dosn’t allcoate the space itself it uses new in the constructor to do so. The class definition declares the num_strings member to belong to the static storage class. Static class members have the special property that only one copy of the class variable is create. This is independent of the number of objects created. Example: I can have ten StringBad objects. They all share the same num_strings variable. Here we are using the variable to keep track of the number of StringBad objects created.

John Chrispell, Monday November 15, 2010 slide 9/25 The StringBad Class

Now lets consider the implementation! // s t r n g b a d . cpp −− StringBad c l a s s methods #include // s t r i n g . h f o r some #include ” s t r n g b a d . h” using s t d : : cout ;

// initializing s t a t i c c l a s s member i n t StringBad :: num s t r i n g s = 0 ;

// c l a s s methods

// c o n s t r u c t StringBad from C s t r i n g StringBad :: StringBad( const char ∗ s ){ len = std::strlen(s); // s e t s i z e s t r = new char [ l e n + 1 ] ; // a l l o t s t o r a g e std::strcpy(str , s); // i n i t i a l i z e p o i n t e r n u m s t r i n g s ++; // s e t o b j e c t count cout << n u m s t r i n g s << ” : \”” << s t r << ”\” o b j e c t c r e a t e d \n” ; // For Your Information }

StringBad :: StringBad() { // d e f a u l t constructor

l e n = 4 ; s t r = new char [ 4 ] ; std::strcpy(str , ”C++” ); // d e f a u l t s t r i n g n u m s t r i n g s ++; cout << n u m s t r i n g s << ” : \”” << s t r << ”\” d e f a u l t o b j e c t c r e a t e d \n” ; // FYI }

StringBad ::˜ StringBad() { // n e c e s s a r y d e s t r u c t o r

cout << ”\”” << s t r << ”\” o b j e c t d e l e t e d , ” ; // FYI −−n u m s t r i n g s ; // r e q u i r e d cout << n u m s t r i n g s << ” l e f t \n” ; // FYI delete [ ] s t r ; // r e q u i r e d }

std::ostream & operator <<(std::ostream & os, const StringBad & st){ os << s t . s t r ; return os ; }

John Chrispell, Monday November 15, 2010 slide 11/25 The StringBad Class

First we set the default: // initializing s t a t i c c l a s s member i n t StringBad :: num s t r i n g s = 0 ; This is because the declaration of the class is a description (in the .h file) and dosn’t actually allocate the memory, it only describes how it is to be allocated. Static class members are also not stored with the objects and should be initialized separately. We do this with the class method definitions and not in the header, as header files tend to get multiple inclusions, and we don’t want to include the initialization more than once.

John Chrispell, Monday November 15, 2010 slide 13/25 The StringBad Class

Each constructor has: n u m s t r i n g s ++; Each destructor has: nu m s t ri n gs −−; The constructor: // c o n s t r u c t StringBad from C s t r i n g StringBad :: StringBad( const char ∗ s ){ len = std::strlen(s); // s e t s i z e s t r = new char [ l e n + 1 ] ; // a l l o t s t o r a g e std::strcpy(str , s); // i n i t i a l i z e p o i n t e r n u m s t r i n g s ++; // s e t o b j e c t count cout << n u m s t r i n g s << ” : \”” << s t r << ”\” o b j e c t c r e a t e d \n” ; // For Your Information } uses strlen to determin how much spaces is needed and allocates the space using new. The default constructor works similarly only uses ”C++” as the string. John Chrispell, Monday November 15, 2010 slide 15/25 The StringBad Class

The destructor is where the important stuff lives: StringBad ::˜ StringBad() { // n e c e s s a r y d e s t r u c t o r

cout << ”\”” << s t r << ”\” o b j e c t d e l e t e d , ” ; // FYI −−n u m s t r i n g s ; // r e q u i r e d cout << n u m s t r i n g s << ” l e f t \n” ; // FYI delete [ ] s t r ; // r e q u i r e d } We used new to create this string we need to use delete to free it!

John Chrispell, Monday November 15, 2010 slide 17/25 Sample Program

#include using s t d : : cout ;

#include ” s t r n g b a d . h” void callme1(StringBad &); // pass by r e f e r e n c e void callme2(StringBad); // pass by v a l u e

i n t main ( ) { using s t d : : e n d l ; StringBad headline1( ” C e l e r y S t a l k s at Midnight ” ); StringBad headline2( ” L e t t u c e Prey ” ); StringBad sports( ” Spinach Leaves Bowl f o r D o l l a r s ” ); cout << ” h e a d l i n e 1 : ” << h e a d l i n e 1 << e n d l ; cout << ” h e a d l i n e 2 : ” << h e a d l i n e 2 << e n d l ; cout << ” s p o r t s : ” << s p o r t s << e n d l ; callme1(headline1 ); cout << ” h e a d l i n e 1 : ” << h e a d l i n e 1 << e n d l ; callme2(headline2 ); cout << ” h e a d l i n e 2 : ” << h e a d l i n e 2 << e n d l ; cout << ” I n i t i a l i z e one o b j e c t to an o t he r : \ n” ; StringBad sailor = sports; cout << ” s a i l o r : ” << s a i l o r << e n d l ; cout << ” A s s i g n one o b j e c t to an o t he r : \ n” ; StringBad knot; knot = headline1; cout << ” knot : ” << knot << e n d l ; cout << ”End o f main () \ n” ;

return 0 ; }

void callme1(StringBad & rsb){ cout << ” S t r i n g passed by r e f e r e n c e : \ n” ; cout << ” \”” << r s b << ”\”\n” ; }

void callme2(StringBad sb){ cout << ” S t r i n g passed by v a l u e : \ n” ; cout << ” \”” << sb << ”\”\n” ; }

John Chrispell, Monday November 15, 2010 slide 19/25 Sample Program

The Program has some issues as written. StringBad sailor = sports; /∗ Same as : ∗/ StringBad sailor = StringBad(sports); This would have a constructor of the type: StringBad ( const StringBad &); And the C++ compiler automatically creates this constructor for us. This is called a copy constructor, and it dosn’t know about the num_strings variable.

John Chrispell, Monday November 15, 2010 slide 21/25 C++ defaults:

C++ automatically provides the following class member functions if you do not: A default constructor. A copy constructor. An assignment operator. A default destructor. An address operator. The last four actually only get created if you use them in a way that C++ deems them a requirement. The implicit copy and implicit assignment operator cause the StringBad class problems.

John Chrispell, Monday November 15, 2010 slide 23/25 Implicit Class Member Functions

The implicit address operator returns the address of the invoking object. The value of the this pointer. This works fine for the StringBad class. The default destructor does nothing and thats also fine for the StringBad class. We will take a more indepth look at Default constructors, Copy constructors, and Assignment constructors next Class. And how to fix the StringBad class.

John Chrispell, Monday November 15, 2010 slide 25/25