330 likes | 421 Vues
Learn about the operators new and delete in C++, how to manipulate free store efficiently, handle memory allocation, and use the scope resolution operator to manage class scopes.
E N D
Today’s Topics • The operators new and delete • The scope resolution operator • Nested classes • Static and const members • The “this” pointer • Constructors and destructors CS410 – Software Engineering Lecture #9: C++ Basics III
The Operators new and delete • The unary operators new and delete are available to manipulate free store. • They are more convenient than the C functions malloc(), calloc(), and free(). • Free store is a system-provided memory pool for objects whose lifetime is directly managed by the programmer. • This adds responsibility to the programmer and can easily lead to problems such as memory leaks. • On the other hand, manipulating free store is an efficient and flexible way to handle data structures such as trees and lists. CS410 – Software Engineering Lecture #9: C++ Basics III
The Operators new and delete • The programmer creates an object using new, and destroys the object using delete. • The operator new is typically used in the following forms: • new type-name • new type-name initializer • new type-name [expression] • In each case, there are at least two effects: • An appropriate amount of store isallocated from free store to contain the named type. • The base address of the object is returned as the value of the new expression. CS410 – Software Engineering Lecture #9: C++ Basics III
The Operators new and delete • Example: • … • int *p, *q; • p = new int(5); • q = new int[10]; • … • In this code, • the pointer variable p is assigned the address of the store obtained, • The location pointed at by p is initialized to the value 5, • the pointer variable q is assigned the base address of an int array of size 10. CS410 – Software Engineering Lecture #9: C++ Basics III
The Operators new and delete • Notice the following things: • When memory is unavailable, the operator new can either throw a bad_alloc exception or return the value 0. • If no initializer is provided, the content of the allocated memory is undefined. • Arrays cannot be initialized using the new operator. • Objects created by the new operator always need to be destroyed by the delete operator as soon as they are not used by the program any more. CS410 – Software Engineering Lecture #9: C++ Basics III
The Operators new and delete • The operator delete destroys an object created by new. • This returns its allocated storage to free store for reuse. • The operator delete is used in the following forms: • delete expression • delete [] expression • The first form is used when the corresponding new expression has not allocated an array. • The second form (empty brackets) is used when the original allocation was an array. • The return type of delete is void (no return value). CS410 – Software Engineering Lecture #9: C++ Basics III
The Operators new and delete • Example: Dynamic allocation of an array • int main() • { • int *data; • int size; • cout << “\nEnter array size: “; • cin >> size; • assert(size > 0); • data = new int[size]; • assert(data != 0); • for (int j = 0; j < size; j++) • cout << (data[j] = j) << ‘\n’; • delete [] data; • return 0; • } Starting the program: Enter array size: 4 0 1 2 3 CS410 – Software Engineering Lecture #9: C++ Basics III
The Scope Resolution Operator • The concept of classes adds new scope rules to those of the kernel language. • You remember that one point of classes is to provide an encapsulation technique. • It makes sense that all names declared within a class be treated within their own scope as distinct from external names, function names, and other class names. • This creates the need for the scope resolution operator. CS410 – Software Engineering Lecture #9: C++ Basics III
The Scope Resolution Operator • The scope resolution operator is the highest-precedence operator in the C++ language. • It comes in two forms: • ::j (unary operator – refers to external scope) • MyClass::j (binary operator – refers to class scope) • Its unary form is used to access a name that has external scope and has been hidden by local or class scope. CS410 – Software Engineering Lecture #9: C++ Basics III
The Scope Resolution Operator • Example: • int count = 0; • void how_many(double w[], double x, int &count) • { • for (int i = 0; i < N; i++) • count += (w[i] == x); // local count • ++ ::count; // global count tracks calls • } CS410 – Software Engineering Lecture #9: C++ Basics III
The Scope Resolution Operator • To better understand this program fragment, we change the parameter int &count to int &cnt: • int count = 0; • void how_many(double w[], double x, int &cnt) • { • for (int i = 0; i < N; i++) • cnt += (w[i] == x); // local count • ++count; // global count tracks calls • } CS410 – Software Engineering Lecture #9: C++ Basics III
The Scope Resolution Operator • Binary scope resolution is used to clarify names that are reused within classes. • For example, we need scope resolution to define member functions: • class Student • { • public: • void PrintName(); • private: • string studentName; • }; void Student::PrintName() { cout << studentName; } CS410 – Software Engineering Lecture #9: C++ Basics III
Nested Classes • Like blocks and namespaces, classes are scopes and can nest. • Nesting allows local hiding of names and local allocation of resources. • This is often desirable when a class is needed as part of the implementation of a larger construct. CS410 – Software Engineering Lecture #9: C++ Basics III
Nested Classes • Example: • char c; // external scope ::c • class X // outer class declaration X:: • { • public: • char c; // X::c • class Y // inner class declaration X::Y:: • { • public: • void foo(char e) { X t; ::c = t.X::c = c = e; } • private: • char c; // X::Y::c • }; • }; t.X::c is the same as t.c CS410 – Software Engineering Lecture #9: C++ Basics III
static and const Members • Using the modifier static in declaring a data member means that the data member is independent of any given class variable. • The data member is part of the class but separate from any single class object. • You remember that nonstatic data members are created for each instance of the class. • Using static data allows class data to be scoped to the class but still require only one object for its storage. • Without static data members, data required by all instances of a class would have to be global. CS410 – Software Engineering Lecture #9: C++ Basics III
static and const Members • Since static members are independent of a particular instance, they can be accessed in the form • class-name :: identifier • Example: • class Point • { • public: • static int how_many; • }; • Point::how_many = 0; • … • ++Point::how_many; CS410 – Software Engineering Lecture #9: C++ Basics III
static and const Members • A static member function has the modifier static precede the return type inside the class declaration. • Example: • class Foo • { • static intfoo_function(); • }; • intFoo::foo_function() • { • … • } CS410 – Software Engineering Lecture #9: C++ Basics III
static and const Members • A data member declared with theconst modifier cannot be modified after initialization. • syntactically, a const member function has the modifier follow the argument list inside the class declaration. • Example: • class Foo • { • intfoo_function() const; • }; • intFoo::foo_function() const {} CS410 – Software Engineering Lecture #9: C++ Basics III
static and const Members • The const and static member function implementation can be understood terms of this pointer access. • An ordinary member function is invoked as x.fcn(i, j, k). • It has an explicit argument list i, j, k and an implicit argument list that includes the members of x (accessible through the this pointer). • A static member function does not get the implicit arguments. • A const member function cannot modify its implicit arguments. CS410 – Software Engineering Lecture #9: C++ Basics III
The this Pointer • The keyword this denotes a self-referential pointer to a class object. • It cannot be used in static member functions. • Example: • class Point • { • public: • void init(double u, double v) { x = u; y = v; } • Point inverse() { x = -x; y = -y; return (*this); } • Point* where_am_I() { return this; } • Private: • double x, y; • }; CS410 – Software Engineering Lecture #9: C++ Basics III
Constructors and Destructors • A constructor is a member function whose name is the same as the class name. • It constructs values of the class type. • This process involves initializing data members and, frequently, allocating free store by using new. • A destructor is a member function whose name is the class name preceded by the ~ character. • It finalizes objects of the class type. • Typically, a destructor deallocates store assigned to the object by using delete. CS410 – Software Engineering Lecture #9: C++ Basics III
Constructors and Destructors • Constructors • can take arguments, • can be overloaded. • A constructor is invoked whenever • its associated type is used in a definition, • call-by-value is used to pass a value to a function, • the return value of a function must create a value of associated type. CS410 – Software Engineering Lecture #9: C++ Basics III
Constructors and Destructors • Destructors • cannot take arguments, • cannot be overloaded. • A destructor is invoked implicitly whenever an object goes out of scope. • Constructors and destructors do not have return types and cannot use return expression statements. CS410 – Software Engineering Lecture #9: C++ Basics III
Classes with Constructors • Example: A data type ModInt for storing numbers that are computed with a modulus. • class ModInt • { • public: • ModInt(int i); // constructor declaration • void assign(int i) { v = i % modulus; } • void print() const {cout << v << ‘\n’; } • const static int modulus; • private: • int v; • }; • ModInt::ModInt(int i) { v = i % modulus; } // constructor definition • const int ModInt::modulus = 60; CS410 – Software Engineering Lecture #9: C++ Basics III
Classes with Constructors • void main() • { • ModInt a(5); • ModInt b(62); • a.print(); • b.print(); • } • What does the output look like? • 5 • 2 CS410 – Software Engineering Lecture #9: C++ Basics III
Classes with Constructors • What happens if we declare a variable c as follows: • ModInt c; • Since this class has only one constructor, and this constructor needs one int argument, this declaration causes a compile-time error. • The declaration above requires a default constructor. CS410 – Software Engineering Lecture #9: C++ Basics III
The Default Constructor • A constructor requiring no arguments is called the default constructor. • It can be a constructor with an empty argument list or one whose arguments all have default values. • It has the special purpose of initializing arrays of objects of its class. • In the ModInt example, it would be useful to define a default value of v to be 0. • To achieve this, we could add the following default constructor: • ModInt() { v = 0; } CS410 – Software Engineering Lecture #9: C++ Basics III
The Default Constructor • main () • { • ModInt s1, s2; • ModInt d[5]; • ModInt s1.print(); • ModInt s2.print(); • ModInt d[3].print(); • } Output: 0 0 0 CS410 – Software Engineering Lecture #9: C++ Basics III
The Default Constructor • If a class does not have a constructor, the system provides a default constructor. • If a class has constructors but no default constructor, array allocation causes a syntactic error. • In our ModInt example, the following constructor could serve as both a general initializer and a default constructor: • ModInt(int i = 0) { v = i % modulus; } CS410 – Software Engineering Lecture #9: C++ Basics III
Constructor Initializers • A special syntax is used for initializing class members. • Constructor initializers for class members can be specified in a comma-separated list that follows the constructor parameter list. • The previous example can be recoded as: • ModInt(int i = 0): v(i % modulus) {} • Notice that initialization replaces assignment. • The individual members must be initializable as member-name (expression list). CS410 – Software Engineering Lecture #9: C++ Basics III
Constructors as Conversions • Constructors of a single parameter are used automatically for conversion unless declared with the keyword explicit. • For example, T1::T1(T2) provides code that can be used to convert a T2 object to a T1 object. • Let us take a look at the following class PrintChar, whose purpose is to print invisible characters with their ASCII designation (for example, the code 07 is alarm or bel). CS410 – Software Engineering Lecture #9: C++ Basics III
Constructors as Conversions • class PrintChar • { • public: • PrintChar(int i = 0) : c(i % 128) {} • void print() const { cout << rep[c]; } • private: • int c; • static const char* rep[128]; • }; • const char *PrintChar::rep[128] = {“nul”, “soh”, “stx”, …, “}”, “~”, “del”}; CS410 – Software Engineering Lecture #9: C++ Basics III
Constructors as Conversions • int main() • { • PrintChar c; • for (inti = 0; i < 128; i++) • { • c = i; // or: c = static_cast<PrintChar>(i); • c.print(); • cout << endl; • } • } • This program prints out the first 128 ASCII characters or their printable representations. CS410 – Software Engineering Lecture #9: C++ Basics III