Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C++ For Mathematicians (2006) [eng]

.pdf
Скачиваний:
194
Добавлен:
16.08.2013
Размер:
31.64 Mб
Скачать

356

C++ for Mathematicians

An alternative method for setting up a variable is to use new. If T is a type, we have the following statements,

T* xp;

xp = new T;

The new statement allocates sizeof(T) bytes of memory for a new object of type T. The zero-argument constructor (if any) is invoked when initializing the new object. Then, a pointer to that new object is assigned to xp. We may supply arguments to the type T constructor using this syntax:

xp = new T(arg1, arg2, ..., argN);

When we use new (as opposed to the ordinary method of declaring variables) the memory for the object does not reside on the stack. Instead, it resides in a different portion of the computer’s memory called the heap. The practical difference is that the object defined using new persists even after the procedure in which it was created ends.

Once the program is finished using an object created with new, the memory allocated to that object should be released. This is done with a delete statement:

delete xp;

Notice that the syntax here is slightly different from the situation in which we are freeing an array; in the latter case we use delete[]. The square brackets indicate that an entire of array of objects is being freed.

Once an object is created using new, it can be used just as any other object. However, we must remember that the variable xp is not of type T, but rather is a pointer to an object of type T. Therefore, if T has a method named, say, reset, it is an error to invoke this method with the expression xp.reset(). Instead, we should write (*xp).reset(). Likewise, to access a data member of this object (say, it has a data element named a), we do not use the expression xp.a; rather, we write (*xp).a.

There is an alternative way to write (*xp).reset() and (*xp).a. The C++ operator -> is defined as follows.

xp->reset() means (*xp).reset(), and

xp->a means (*xp).a.

The combination of a hyphen and a greater-than symbol is meant to look like an arrow pointing to the part of *xp we want.

15.6.5 Why use pointers?

There are a few situations in which pointers are useful, but in nearly all cases, one can do fine without them. Before call by reference was introduced into C++, procedures written in C that needed to modify their arguments used pointers instead of the values of the variables. For example, a procedure to swap the values of two double variables would be written like this:

Odds and Ends

357

void swap(double* a, double* b) { double tmp = *a;

*a = *b; *b = tmp;

}

To use this swap procedure on variables x and y of type double, we would write swap(&x,&y);. The ampersands are necessary because this version of swap requires pointer-to-double arguments.

Similarly, suppose T is a class and that objects of type T are large (say, hundreds of bytes). Then each time we pass an object of type T to a procedure, the object is duplicated. Where possible, we can improve efficiency by passing a reference to the object instead of using call by value. Alternatively, we can declare the procedure’s argument to be of type pointer-to-T. Passing a pointer is efficient, but we need to remember to pass the address of the object, and not the object itself. This is summarized in the following chart:

Declaration

Invocation

Efficiency

void proc(T x) {...}

proc(x);

slow

void

proc(const T& x) { ... }

proc(x);

fast

void

proc(T* x) { ... }

proc(&x);

fast

There is a natural way to avoid using new to create new instances of objects in the heap. Recall that primary purpose for doing this is to avoid passing large objects to and from a procedure. For example, a graph theory package would naturally include a procedure for partitioning the vertex set into connected components. This hypothetical procedure, named components, would take a single argument (of type Graph) and return a partition. The standard way to define such a procedure is like this:

Partition components(Graph g) { Partition p;

// ...

return p;

}

Then, when we have the statement P = components(G); the computer would first make a copy of G (to be held in g inside the procedure). Then the Partition computed by the procedure (p) is copied back to the calling procedure to be saved in P. If the graph is large, this is highly inefficient.

Some programmers would solve this problem by using pointers. In that paradigm, the procedure would look like this:

Partition* components(Graph* gp) { Partition* pp;

pp = new Partition; // ...

return pp;

}

358

C++ for Mathematicians

To invoke this procedure, we use a statement like this: P_ptr=components(&G);. Now G does not have to be copied; a pointer to G is all that needs to be sent to the procedure and a pointer to the newly calculated partition is all that needs to be sent back. It is then incumbent on the programmer to remember to delete pp; or else suffer a memory leak.

There is a better, third alternative. We can use call-by-reference parameters to prevent repeated copying, and avoid pointers altogether. In this case, we define the procedure like this:

void components(const Graph& g, Partition& p) { // calculate p from g

}

In this case, we call the procedure with a statement of the form components(G,P);. The procedure would begin by erasing any data that happen to be in P and then overwriting with the new partition.

Thankfully, there are hardly any situations in C++ that require the use of a pointer. You may be required to use pointers when using other people’s packages. An instance of this is the Standard Template Library’s sort procedure (see Section 7.4).

Every method in a class may use a pointer named this. The this pointer refers to the object that invoked the method; that is, if we call X.method(), then method may use a pointer named this that points to X. This is handy if method modifies X and then wants to return a copy of X. This behavior is desirable when defining operators such as += for a class. See Section 6.8.

15.7Exercises

15.1Create a Card class to represent cards from a standard 52-card deck. The class should have the following features.

A zero-argument constructor that creates a default card (say, the ace of spades) and a two-argument constructor that sets the the value and suit of the card. The user should be able to create cards such as this:

Card boss(ACE,SPADES);

Card weak(2, CLUBS);

Comparison operators <, ==, and !=.

An operator<< for writing cards to the screen in English words, such as

ace of spades or four of diamonds.

15.2 What is the difference between the following two statements?

T* xp = new T(10);

T* xp = new T[10];

Odds and Ends

359

15.3In Exercise 5.11 you were asked to create a program that repeatedly asked for large blocks of memory by using new without balancing calls to delete[]. When new is unable to allocate space (because memory has been exhausted), it throws an exception of type std::bad_alloc. Revise your program so that it exits gracefully (instead of crashing) when memory is exhausted.

15.4C++ uses punctuation symbols for a variety of purposes. Many of these symbols serve multiple purposes in the language. For example, * is used for multiplication and for declaring arrays (and for a few other purposes). In addition, these symbols can be doubled (e.g., & versus &&) or combined with others (e.g., !=) to form additional meanings.

Find as many meanings for these symbols (either singly or in combination) as you can:

+ - * / = < > ! & | ˜ :

Don’t bother listing all of the combined arithmetic/assign operators such as +=. Classes may overload many of these symbols; list only the standard overloads.

15.5Create a class named Constructible to represent numbers that can be determined using the classical construction tools: straight edge and compass.

Specifically, define constructible numbers recursively by declaring that all integers are constructible; the sum, difference, product, and quotient6 of con-

structible numbers are constructible; and the square root of a constructible number is constructible. The complex numbers that can be built this way correspond to points in the plane that can be constructed using a straight edge, a compass, and a given unit length.

The objects in this class should represent their numbers exactly. That is, the p

number 2 + 5 − 2 should be held as such, and not as a decimal (double) approximation.

This class should include the following methods.

A zero-argument constructor to create the constructible number zero.

A one-argument constructor that takes a long integer argument.

A copy constructor.

A destructor.

An assignment operator.

The binary operators + - * / (either two Constructible arguments or a Constructible and a long integer) and unary -.

A sqrt() method that returns the square root of the constructible number on which it was invoked.

6Of course, division by zero is forbidden.

360

C++ for Mathematicians

A value() method that returns a complex<double> value giving the approximate decimal value of the constructible number.

An operator<< procedure that writes the number to an output stream in a suitable format such as TEX

2 + \sqrt{5 - \sqrt{2}}

or Mathematica

2 + Sqrt[5 - Sqrt[2]]

or some sensible method of your choosing.

15.6Tautology Checker. Create a program to check if Boolean expressions are tautologies. A Boolean expression is an algebraic expression involving variables (a, b, c, . . . ) and logical operations (and, or, not, implies, iff, etc.). A tautology is a Boolean expression that evaluates to TRUE for all possible truth values of its variables. For example, ((x → y) x) → y is a tautology.

The program should be invoked either (a) with a command-line argument specifying a file that contains the Boolean expression to be tested, or (b) with no command-line argument, in which case the user is prompted to type in the Boolean expression.

The variable names may be any single lowercase letter (a to z). Use the following for operation symbols.

Symbol

Meaning

+

or

*

and

-

not

>

implies →

<

implied by ←

=

equivalent ↔

0

TRUE

1

FALSE

 

 

Use reverse Polish notation (RPN) for the expressions (these are easier to process than ordinary algebraic expressions). For example, the expression ((x → y) x) → y would be entered as x y > x * y >. Spaces are optional, so this may also be entered as xy>x*y>.

It may be convenient for the user to enter an expression over several lines. The user should indicate that the expression is finished by typing a period.

Part IV

Appendices

Appendix A

Your C++ Computing Environment

The methods by which you type, compile, and run programs varies between different computers with different operating systems.

There are two broad approaches to this edit/compile/run process.

You use separate tools in terminal windows. That is, you type commands in a window to invoke an editor for creating and modifying your C++ files, type another command to compile your code, and another command to run the program.

The code in this book was developed using the emacs editor and compiled using the g++ compiler. These tools are available for many computer systems (Windows, Macintosh, UNIX) and available for free from the Free Software Foundation (www.gnu.org).

You use an integrated development environment (IDE). This is a software application that provides a built-in text editor (for creating and modifying your code), a compiler, a debugger, and a means to run your program. Such environments include Microsoft’s Visual Studio on Windows computers, Apple’s Xcode on Macintosh OS X, KDevelop on Linux, and Metrowerk’s Code Warrior which runs on several platforms.

Which approach you prefer is a matter of taste. The installation of these tools ranges from simple to complex. You may need some assistance from a friendly computer science colleague in getting started. If you can type in the code in Program 1.1, compile it, and run, then you are well under way!

In this Appendix we provide specific advice to help you get started programming.

A.1 Programming with a command window and a text editor

In this approach your work is performed using two windows: a text editor and command shell. The specific tools we discuss come from the Gnu/UNIX world, but are available for Windows, Macintosh, Linux, and many other systems. It is possible that these tools are already present on your computer (especially if you are using Linux or some variation of UNIX).

363

364

C++ for Mathematicians

A.1.1 What you need and how to get it (for free)

To program in this manner you require the following.

A shell command window (running sh or one of its variants such as bash or csh).

A text editor (the emacs or Xemacs editor, or some other editor designed for programming).

A C++ compiler (such as g++ from Gnu).

The make program to automate the compiling process (optional).

The Doxygen program for creating Web-based documentation for your own program (optional). See Appendix B.

If you are using a UNIX computer, these tools are likely to be already installed. For Windows and Macintosh users, you have the following options.

Cygwin on Windows

For Windows, we recommend that you install Cygwin (available for free from www.cygwin.com). This is a system that provides UNIX-like tools including the pieces you need: a bash terminal window, the g++ compiler, emacs and Xemacs text editors, and the make program.

Follow the download and installation directions at the Cygwin Web site (see “Setting Up Cygwin”).

Next, run the setup.exe program which presents you with a long list (separated into categories) of packages to install. Select the packages you want to install. We recommend the following.

bash doxygen emacs emacs-X11 gcc gcc-g++ make xemacs

xorg-x11-xwin xterm

The Cygwin setup program may install other packages that you did not select because it understands how the packages you want depend on other packages. For example, selecting the xemacs package triggers the inclusion of other packages needed to provide the X-window environment.

If all has gone well, new entries will be present in your Start menu, including an entry to start a bash shell:

Start > Programs > Cygwin > Cygwin Bash Shell

Your C++ Computing Environment

365

Macintosh tools

Macintosh OS X comes with many of the tools you need. For example, the Terminal application launches a bash shell.

If X11 has not been installed (see the Utilities folder inside the Applications folder), then install it using the disks (CD/DVD-ROM) that came with your computer.

You need the Developer Tools. Check if there is a folder named Developer at the top level of your hard drive (and be sure that inside that folder there is a subfolder named Applications containing the Xcode application). Alternatively, open a Terminal window and type the command: g++ --version. If the computer complains g++: command not found then you need to install the Developer Tools, but if it responds with the version of g++ installed, then you know that the compiler is already installed on your computer. The make program should also be installed (try make --version).

If the Developer Tools are not on your computer, they are either available on the disks that came with your computer or you can download them (for free) from Apple’s Web site (developer.apple.com). Get a free membership to their Developer Connection, navigate to Developer Tools, and download Xcode.

Next you need a text editor such as emacs. You can find Macintosh-style versions of emacs for free on the Web; see:

http://home.att.ne.jp/alpha/z123/emacs-mac-e.html

Finally, install the Doxygen application, available for free from doxygen.org. This is a standard Macintosh application that you install simply by dragging its icon to your Applications folder. (See Appendix B.)

A.1.2 Editing program files

To create the files for your C++ project you need a text editor such as emacs. Do not use a word processor, such as Microsoft Word, for this purpose.

A good programming editor makes your life easier. As you type your program, the editor automatically indents lines of code the proper amount so you can see the structure. It also highlights keywords in color. If, for some reason, the editor does not indent your typing the distance you expect or a keyword does not appear in color, then you have a quick visual clue that you mistyped something. Smart text editors (such as emacs) detect what sort of file you are editing and place you into an appropriate mode1 for that sort of file.

Begin by creating a folder (directory) where you want to save your program. If you wish to use code you have already created for another project (or code from this book on the accompanying CD), you can copy the files you want into this directory.

1In emacs, editing a .h file places you in an editing mode meant for C, and not for C++. To switch to C++ mode, type: M-x c++-mode where M-x means “meta-x”.