⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 e.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 5 页
字号:
}This version of operator<< demonstrates some subtle (but important) points that are discussed elsewhere in this book. For example, operator<< is not a member function (Item 19 explains why), and the Rational object to be output is passed into operator<< as a reference-to-const rather than as an object (see Item 22). The corresponding input function, operator>>, would be declared and implemented in a similar manner.Reluctant though I am to admit it, there are some situations in which it may make sense to fall back on the tried and true. First, some implementations of iostream operations are less efficient than the corresponding C stream operations, so it's possible (though unlikely see Item M16) that you have an application in which this makes a significant difference. Bear in mind, though, that this says nothing about iostreams in general, only about particular implementations; see Item M23. Second, the iostream library was modified in some rather fundamental ways during the course of its standardization (see Item 49), so applications that must be maximally portable may discover that different vendors support different approximations to the standard. Finally, because the classes of the iostream library have constructors and the functions in <stdio.h> do not, there are rare occasions involving the initialization order of static objects (see Item 47) when the standard C library may be more useful simply because you know that you can always call it with impunity.The type safety and extensibility offered by the classes and functions in the iostream library are more useful than you might initially imagine, so don't throw them away just because you're used to <stdio.h>. After all, even after the transition, you'll still have your memories.Incidentally, that's no typo in the Item title; I really mean <iostream> and not <iostream.h>. Technically speaking, there is no such thing as <iostream.h> the standardization committee eliminated it in favor of <iostream> when they truncated the names of the other non-C standard header names. The reasons for their doing this are explained in Item 49, but what you really need to understand is that if (as is likely) your compilers support both <iostream> and <iostream.h>, the headers are subtly different. In particular, if you #include <iostream>, you get the elements of the iostream library ensconced within the namespace std (see Item 28), but if you #include <iostream.h>, you get those same elements at global scope. Getting them at global scope can lead to name conflicts, precisely the kinds of name conflicts the use of namespaces is designed to prevent. Besides, <iostream> is less to type than <iostream.h>. For many people, that's reason enough to prefer it. Back to Item 2: Prefer <iostream> to <stdio.h>.Continue to Item 4: Prefer C++-style comments.Item 3: Prefer new and delete to malloc and free.The problem with malloc and free (and their variants) is simple: they don't know about constructors and destructors.Consider the following two ways to get space for an array of 10 string objects, one using malloc, the other using new: string *stringArray1 =  static_cast<string*>(malloc(10 * sizeof(string)));string *stringArray2 = new string[10];Here stringArray1 points to enough memory for 10 string objects, but no objects have been constructed in that memory. Furthermore, without jumping through some rather obscure linguistic hoops (such as those described in Items M4 and M8), you have no way to initialize the objects in the array. In other words, stringArray1 is pretty useless. In contrast, stringArray2 points to an array of 10 fully constructed string objects, each of which can safely be used in any operation taking a string.Nonetheless, let's suppose you magically managed to initialize the objects in the stringArray1 array. Later on in your program, then, you'd expect to do this: free(stringArray1);delete [] stringArray2;      // see Item 5 for why the                             // "[]" is necessaryThe call to free will release the memory pointed to by stringArray1, but no destructors will be called on the string objects in that memory. If the string objects themselves allocated memory, as string objects are wont to do, all the memory they allocated will be lost. On the other hand, when delete is called on stringArray2, a destructor is called for each object in the array before any memory is released.Because new and delete interact properly with constructors and destructors, they are clearly the superior choice.Mixing new and delete with malloc and free is usually a bad idea. When you try to call free on a pointer you got from new or call delete on a pointer you got from malloc, the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces.The incompatibility of new/delete and malloc/free can lead to some interesting complications. For example, the strdup function commonly found in <string.h> takes a char*-based string and returns a copy of it: char * strdup(const char *ps);      // return a copy of what                                    // ps points toAt some sites, both C and C++ use the same version of strdup, so the memory allocated inside the function comes from malloc. As a result, unwitting C++ programmers calling strdup might overlook the fact that they must use free on the pointer returned from strdup. But wait! To forestall such complications, some sites might decide to rewrite strdup for C++ and have this rewritten version call new inside the function, thereby mandating that callers later use delete. As you can imagine, this can lead to some pretty nightmarish portability problems as code is shuttled back and forth between sites with different forms of strdup.Still, C++ programmers are as interested in code reuse as C programmers, and it's a simple fact that there are lots of C libraries based on malloc and free containing code that is very much worth reusing. When taking advantage of such a library, it's likely you'll end up with the responsibility for freeing memory malloced by the library and/or mallocing memory the library itself will free. That's fine. There's nothing wrong with calling malloc and free inside a C++ program as long as you make sure the pointers you get from malloc always meet their maker in free and the pointers you get from new eventually find their way to delete. The problems start when you get sloppy and try to mix new with free or malloc with delete. That's just asking for trouble.Given that malloc and free are ignorant of constructors and destructors and that mixing malloc/free with new/delete can be more volatile than a fraternity rush party, you're best off sticking to an exclusive diet of news and deletes whenever you can. Back to Item 3: Prefer new and delete to malloc and free.Continue to Memory ManagementItem 4: Prefer C++-style comments.The good old C comment syntax works in C++ too, but the newfangled C++ comment-to-end-of-line syntax has some distinct advantages. For example, consider this situation: if ( a > b ) {  // int temp = a;    // swap a and b  // a = b;  // b = temp;}Here you have a code block that has been commented out for some reason or other, but in a stunning display of software engineering, the programmer who originally wrote the code actually included a comment to indicate what was going on. When the C++ comment form was used to comment out the block, the embedded comment was of no concern, but there could have been a serious problem had everybody chosen to use C-style comments: if ( a > b ) {  /*  int temp = a;  /* swap a and b */      a = b;      b = temp;  */}Notice how the embedded comment inadvertently puts a premature end to the comment that is supposed to comment out the code block.C-style comments still have their place. For example, they're invaluable in header files that are processed by both C and C++ compilers. Still, if you can use C++-style comments, you are often better off doing so.It's worth pointing out that retrograde preprocessors that were written only for C don't know how to cope with C++-style comments, so things like the following sometimes don't work as expected: #define LIGHT_SPEED   3e8    // m/sec (in a vacuum)Given a preprocessor unfamiliar with C++, the comment at the end of the line becomes part of the macro! Of course, as is discussed in Item 1, you shouldn't be using the preprocessor to define constants anyway. Back to Item 4: Prefer C++-style comments.Continue to Item 5: Use the same form in corresponding uses of new and delete.Memory ManagementMemory management concerns in C++ fall into two general camps: getting it right and making it perform efficiently. Good programmers understand that these concerns should be addressed in that order, because a program that is dazzlingly fast and astoundingly small is of little use if it doesn't behave the way it's supposed to. For most programmers, getting things right means calling memory allocation and deallocation routines correctly. Making things perform efficiently, on the other hand, often means writing custom versions of the allocation and deallocation routines. Getting things right there is even more important.On the correctness front, C++ inherits from C one of its biggest headaches, that of potential memory leaks. Even virtual memory, wonderful invention though it is, is finite, and not everybody has virtual memory in the first place.In C, a memory leak arises whenever memory allocated through malloc is never returned through free. The names of the players in C++ are new and delete, but the story is much the same. However, the situation is improved somewhat by the presence of destructors, because they provide a convenient repository for calls to delete that all objects must make when they are destroyed. At the same time, there is more to worry about, because new implicitly calls constructors and delete implicitly calls destructors. Furthermore, there is the complication that you can define your own versions of operator new and operator delete, both inside and outside of classes. This gives rise to all kinds of opportunities to make mistakes. The following Items (as well as Item M8) should help you avoid some of the most common ones. Back to Memory ManagementContinue to Item 6: Use delete on pointer members in destructors.Item 5: Use the same form in corresponding uses of new and delete.What's wrong with this picture? string *stringArray = new string[100];...delete stringArray;Everything here appears to be in order the use of new is matched with a use of delete but something is still quite wrong: your program's behavior is undefined. At the very least, 99 of the 100 string objects pointed to by stringArray are unlikely to be properly destroyed, because their destructors will probably never be called.When you use new, two things happen. First, memory is allocated (via the function operator new, about which I'll have more to say in Items 7-10 as well as Item M8). Second, one or more constructors are called for that memory. When you use delete, two other things happen: one or more destructors are called for the memory, then the memory is deallocated (via the function operator delete see Items 8 and M8). The big question for delete is this: how many objects reside in the memory being deleted? The answer to that determines how many destructors must be called.Actually, the question is simpler: does the pointer being deleted point to a single object or to an array of objects? The only way for delete to know is for you to tell it. If you don't use brackets in your use of delete, delete assumes a single object is pointed to. Otherwise, it assumes that an array is pointed to: string *stringPtr1 = new string;string *stringPtr2 = new string[100];...delete stringPtr1;           // delete an objectdelete [] stringPtr2;        // delete an array of                             // objectsWhat would happen if you used the "[]" form on stringPtr1? The result is undefined. What would happen if you didn't use the "[]" form on stringPtr2? Well, that's undefined too. Furthermore, it's undefined even for built-in types like ints, even though such types lack destructors. The rule, then, is simple: if you use [] when you call new, you must use [] when you call delete. If you don't use [] when you call new, don't use [] when you call delete.This is a particularly important rule to bear in mind when you are writing a class containing a pointer data member and also offering multiple constructors, because then you've got to be careful to use the same form of new in all the constructors to initialize the pointer member. If you don't, how will you know what form of delete to use in your destructor? For a further examination of this issue, see Item 11.This rule is also important for the typedef-inclined, because it means that a typedef's author must document which form of delete should be employed when new is used to conjure up objects of the typedef type. For example, consider this typedef: typedef string AddressLines[4];      // a person's address                                     // has 4 lines, each of                                     // which is a stringBecause AddressLines is an array, this use o

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -