c++ primer笔记18: exception

1. Standard exception Class Hierarchy

2. User-Defined Exception Types

class out_of_stock: public std::runtime_error {
public:
explicit out_of_stock(const std::string &s):std::runtime_error(s)
{ }

};
class isbn_mismatch: public std::logic_error {
public:
explicit isbn_mismatch(const std::string &s): std::logic_error(s)
{ }

isbn_mismatch(const std::string &s, const std::string &lhs, const std::string &rhs):
std::logic_error(s), left(lhs), right(rhs) { }
const std::string left, right;
virtual ~isbn_mismatch() throw() { }
};

3. Automatic Resource Deallocation

We know that local objects are automatically destroyed when an exception occurs. The fact that destructors are run has important implication for the design of applications.

void f()
{

vector<string> v; // local vector
string s;
while (cin >> s)
v.push_back(s); // populate the vector
string *p = new string[v.size()]; // dynamic array
// remaining processing
// it is possible that an exception occurs in this code
// function cleanup is bypassed if an exception occurs
delete [] p;
} // v destroyed automatically when the function exits

If an exception occurs inside the function, then the vector will be destroyed but the array will not be freed. The problem is that the array is not freed automatically. No matter when an exception occurs, we are guaranteed that the vector destructor is run.

4. Using Classes to Manage Resource Allocation

The fact that destructors are run leads to an important programming technique that makes programs more exception safe . By exception safe, we mean that the programs operate correctly even if an exception occurs. In this case, the “safety” comes from ensuring that any resouce that is allocated is properly freed if an exception occurs. We can guarantee that resources are properly freed by defining a class to encapsulate the acquisition and release of a resource.

5. The auto_ptr Class

The standard-library auto_ptr class is an example of the exception-safe “resource allocation is initialization” technique. The aut_ptr class is a template that takes a single type parameter. It provides exception safety for dynamically allocated
objects. The auto_ptr class is defined in the memory header. auto_ptr can be used only to manage single objects returned from
new. It does not manage dynamically allocated arrays. As we’ll see, auto_ptr has unusual behavior when copied or assigned. As a result, auto_ptrs may not be stored in the library container types.

void f()
{

int *ip = new int(42); // dynamically allocate a new object
// code that throws an exception that is not caught inside f
delete ip; // return the memory before exiting
}
void f()
{

auto_ptr<int> ap(new int(42)); // allocate a new object
// code that throws an exception that is not caught inside f
}
// auto_ptr freed automatically when function ends

Class auto_ptr  
auto_ptr<T> ap Create an unbound auto_ptr named ap.
auto_ptr<T> ap(p) Create an auto_ptr named ap that owns the object pointed to by the pointer p. This constructor is explicit.
auto_ptr<T> ap1(ap2) Create an auto_ptr named ap1 that holds the pointer originally stored in ap2. Transfers ownership to ap1; ap2 becomes an unbound auto_ptr.
ap1 = ap2 Transfers ownership from ap2 to ap1. Deletes the object to which ap1 points and makes ap1 point to the object to which ap2 points, making ap2 unbound.
~ap Destructor. Deletes the object to which ap points.
*ap Returns a reference to the object to which ap is bound.
ap-> Returns the pointer that ap holds.
ap.reset(p) If the pointer p is not the same value as ap holds, then it deletes the object to which ap points and binds ap to p.
ap.release() Returns the pointer that ap had held and makes ap unbound.
ap.get() Returns the pointer that ap holds.

To determine whether the auto_ptr object refers to an object, we can compare the return from get with 0. get should be used only to interrogate an auto_ptr or to use the returned pointer value. get should not be used as an argument to create another auto_ptr. Using get member to initialize another auto_ptr violates the class design principle that only one auto_ptr holds a given pointer at any one time. If two auto_ptrs hold the same pointer, then the pointer will be deleted twice.

6. Copy and Assignment on auto_ptr Are Destructive Operations

When we copy an auto_ptr or assign its value to another auto_ptr, ownership of the underlying object is transferred from the original to the copy. The original auto_ptr is reset to an unbound state. Unlike other copy or assignment operations, auto_ptr copy and assignment change the right-hand operand. As a result, both the left- and right-hand operands to assignment must be
modifiable lvalues. Because copy and assignment are destructive operations, auto_ptrs cannot be stored in the standard containers. The library container classes require that two objects be equal after a copy or assignment. This requirement is not met by auto_ptr. If we assign ap2 to ap1, then after the assignment ap1 != ap2.

7. Caution: Auto_ptr Pitfalls

The auto_ptr class template provides a measure of safety and convenience for handling dynamically allocated memory. To use auto_ptr correctly, we must adhere to the restrictions that the class imposes:

  • Do not use an auto_ptr to hold a pointer to a statically allocated object. Otherwise, when the auto_ptr itself is destroyed, it will attempt to delete a pointer to a nondynamically allocated object, resulting in undefined behavior.
  • Never use two auto_ptrs to refer to the same object. One obvious way to make this mistake is to use the same pointer to initialize or to reset two different auto_ptr objects. A more subtle way to make this mistake would be to use the result from get on one auto_ptr to initialize or reset another.
  • Do not use an auto_ptr to hold a pointer to a dynamically allocated array. When the auto_ptr is destroyed, it frees only a single objectit uses the plain delete operator, not the array delete [] operator.
  • Do not store an auto_ptr in a container. Containers require that the types they hold define copy and assignment to behave similarly to how those operations behave on the built-in types: After the copy (or assignment), the two objects must have the same value. auto_ptr does not meet this requirement.