![]() |
|
![]() |
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
![]() |
![]() |
[an error occurred while processing this directive]
Comments Youre probably asking yourself, Why have two different access methods, namely operator [] and the at() member function, to perform the same operation? Seemingly, this duality is redundant. However, it isnt. In real-world situations, two additional factors not addressed so far will influence your design: performance and safety. This is where these accessing methods differ. The overloaded [] operator was designed by the C++ Standardization Committee to be as efficient as the subscript operator of a built-in array was. Therefore, it does not check whether its argument actually refers to a valid member. Using an illegal subscript yields undefined behavior. However, the lack of runtime checks also ensures the fastest access time (the overloaded operator [] is usually inline, so the overhead of a function call is avoided). When performance is paramount, and when the code is written carefully so that only legal subscripts are accessed, you should use the subscript operator. It is also more readable and intuitive. Nonetheless, runtime checks are unavoidable under some circumstances. at() is less efficient than operator [], but it is safer because it performs range checking. In an attempt to access an out-of-range member, it throws an exception of type std::out_of_range. Indeed, the samples did not have any try blocks or catch statements surrounding every invocation of at(). This is because the samples were carefully crafted and tested not to access an out-of-range subscript. In large-scale projects, that cannot always guaranteed. Sometimes the subscript argument is received from an external source: a function, a database record, a network message, or a human operator. Keeping track of every vector object and its current valid number of members is impractical in large applications. In these cases, it is advisable to let the underlying mechanism handle access violations in an automated and well-behaved manner; for example, throw an exception rather than let the program corrupt its memory, or crash. When at() is used, your code has to handle a std::out_of_range exception, as in the following example: #include <vector> #include <iostream> #include <string> using namespace std; void main() { try { vector<string> vs; // vs has no elements currently cout<< vs.at(0) <<endl; //oops! no elements exist in vs; exception thrown } catch(std::out_of_range & except) { // diagnostics and remedies for an out-of-range subscript } catch(...) //handle all other exception, e.g., memory exhausted { // do something } }//end main Note that exception handling incurs runtime overhead and larger executable size. C++ leaves you the choice. 7.4 Use a generic LIFO data model?Problem I need a data model that simulates a function call chain. The first function calls another one and so on, until the lowermost function has been called. When the lowermost function exits, control is returned to its caller, and so forth. Technique A stack, also termed last-in-first-out (LIFO), is an ideal data model to implement a function call chain. This How-To will use the STLs stack container. A comprehensive explanation of how to implement a full-blown function call mechanism or how to simulate an exception handling mechanism is well beyond the scope of this book. This How-To only focuses on the data model aspects of the implementation. Exception handling (EH) in C++, as you will read in the following chapters, works in a LIFO model. When an exception is thrown by a function, the EH mechanism tries to locate a corresponding handler (a catch statement) for this particular exception in the current function. If such a handler does not exist, the exception is propagated to the function one level higher in the calling chainthat is, the function from which the current one was called and the current function is exited. This process is repeated until a handler is reached or the program is aborted. The highest function in the calling chain, main(), is the first element pushed into the stack. Next is a function called from main() that is pushed into the call stack, and so on. When an exception is thrown and no appropriate handler can be found, the stack is popped, meaning the lowermost function in the calling chain is removed from the stack and control is returned to the caller. This process is reiterated until the stack has been emptied, which in our case means program abortion. Steps
|
![]() |
Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.
|