Xem mẫu

initialization before the object is used, thus reintroducing a major source of bugs. It also turns out that many programmers seem to find C’s dynamic memory functions too confusing and complicated; it’s not uncommon to find C programmers who use virtual memory machines allocating huge arrays of variables in the static storage area to avoid thinking about dynamic memory allocation. Because C++ is attempting to make library use safe and effortless for the casual programmer, C’s approach to dynamic memory is unacceptable. operator new The solution in C++ is to combine all the actions necessary to create an object into a single operator called ne . When you create an object with new (using a new-expression), it allocates enough storage on the heap to hold the object and calls the constructor for that storage. Thus, if you say MyType *fp = new MyType(1,2); at runtime, the equivalent of malloc(sizeof(MyType)is called (often, it is literally a call to malloc( ), and the constructor for MyType is called with the resulting address as the this pointer, using (1,2) as the argument list. By the time the pointer is assigned to fp, it’s a live, initialized object – you can’t even get your hands on it before then. It’s also automatically the proper MyType type so no cast is necessary. The default new checks to make sure the memory allocation was successful before passing the address to the constructor, so you don’t have to explicitly determine if the call was successful. Later in the chapter you’ll find out what happens if there’s no memory left. You can create a new-expression using any constructor available for the class. If the constructor has no arguments, you write the new-expression without the constructor argument list: 580 Thinking in C++ www.BruceEckel.com MyType *fp = new MyType; Notice how simple the process of creating objects on the heap becomes – a single expression, with all the sizing, conversions, and safety checks built in. It’s as easy to create an object on the heap as it is on the stack. operator delete The complement to the new-expression is the delete-expression, which first calls the destructor and then releases the memory (often with a call to free( ). Just as a new-expression returns a pointer to the object, a delete-expression requires the address of an object. delete fp; This destructs and then releases the storage for the dynamically allocated MyType object created earlier. delete can be called only for an object created by ne . If you malloc( ) (or calloc( ) or realloc( ) an object and then delete it, the behavior is undefined. Because most default implementations of new and delete use malloc( ) and free( , you’d probably end up releasing the memory without calling the destructor. If the pointer you’re deleting is zero, nothing will happen. For this reason, people often recommend setting a pointer to zero immediately after you delete it, to prevent deleting it twice. Deleting an object more than once is definitely a bad thing to do, and will cause problems. A simple example This example shows that initialization takes place: //: C13:Tree.h #ifndef TREE_H #define TREE_H #include 13: Dynamic Object Creation 581 class Tree { int height; public: Tree(int treeHeight) : height(treeHeight) {} ~Tree() { std::cout << "*"; } friend std::ostream& operator<<(std::ostream& os, const Tree* t) { return os << "Tree height is: " << t->height << std::endl; } }; #endif // TREE_H ///:~ //: C13:NewAndDelete.cpp // Simple demo of new & delete #include "Tree.h" using namespace std; int main() { Tree* t = new Tree(40); cout << t; delete t; } ///:~ We can prove that the constructor is called by printing out the value of the Tre . Here, it’s done by overloading the operator< using namespace std; class Object { void* data; // Some storage const int size; const char id; public: Object(int sz, char c) : size(sz), id(c) { data = new char[size]; cout << "Constructing object " << id << ", size = " << size << endl; } ~Object() { cout << "Destructing object " << id << endl; delete []data; // OK, just releases storage, // no destructor calls are necessary } }; int main() { Object* a = new Object(40, `a`); delete a; void* b = new Object(40, `b`); delete b; } ///:~ 584 Thinking in C++ www.BruceEckel.com ... - tailieumienphi.vn