original articles, reproduced please specify the source:http://blog.csdn.net/sfh366958228/article/details/38706483
Chat
These two days are first in the subway to see the meeting effective C + + ", and then back to the company to continue to see, at first because the subway too much boring, cell phone also no signal, you can look at the contents of the discovery of more and more" grounding gas ", began a little unable to extricate themselves.
Today is still looking to find themselves interested in the beginning to see, first back to clause 02, then the design and statement to read, to see today's harvest.
clause 02: Replace # define as const,enum,inline as possible
Before that, # define has always been a way I prefer to use, basically the constants have to be proposed to #define,max, MIN, PI constant almost every day to meet, but also often do not use a # define a constant friend "pointing point." A joke, it's a little exaggerated, but # define is still widely used in many programmers.
# define is actually a pre-processing command that replaces the call to its value directly in the preprocessing phase, so # define does not participate in the compilation, the compiler does not know the existence of # define, OK, then start "interrogates" The disadvantage of # define.
# define PI = 3.1415927
If you define a PI constant, and then there is an error in PI, In the compiler error prompt can only see 3.1415927, then you have to look for 3.1415927, if the pi is defined in a header file that you do not write, you certainly have no concept of it, so you will have to trace the constant to a lot of trouble.
The solution is to replace the macro with a constant:
Const double PI = 3.1415927;
There are two special cases when we use const to replace # define.
The first is to define a constant pointer, such as a char* string, and you have to write the Const two times:
const char * Const DESC = "Hello world!";
Well, in fact, string is better than char*, so it's often defined like this:
CONST std::string DESC ("Hello world!");
The second special case is the exclusive constant of class, so remember to declare it as a static member in order to ensure that the constant has at most one copy.
Speaking of which is not hard to find the other drawback of #defne is that it is impossible to define class-specific constants, because there is no such thing as private # # ...
If your compiler does not allow the static integer class constant to complete the in class initial setting, you can use the enum hack instead.
An enum is like a # define, but not a # define, for example it can not take an address, but the constants defined by the enum are not replaced at the time of preprocessing, but at compile time.
#define用的比较多的另一个地方是定义看起来像函数的宏, the benefit is that there is no additional overhead associated with function calls, such as:
There are too many drawbacks to such a macro, such as you have to give all the arguments with parentheses, or it might make the function appear not the effect you want to see.
You can substitute the template inline function at this time.
Template<typename t>inline void Callwithmax (const t &a, const T &b) {f (a > B? a:b);}
It can have its own scope, and there is no need to worry about enclosing parentheses on the actual use.
But pre-processing commands still have their use, not a stick to kill, but as far as possible to avoid using them.
Summarize:
1) for simple constants, it is best to replace # define with a const object or enum.
2) for macros that resemble functions, it is best to replace the # define with the inline function instead
clause 03: Use of const as far as possible (not finished, to be continued)
Using const to constrain an object to be immutable, for a long time, if the object is set to private, is not understood by me, but as more and more programs are written, there is a new view-your program is not written for yourself.
You have to manually specify whether an object can be changed, so as not to be used when others have unexpected errors, but the compiler did not error, the user will not realize, on the contrary, as a normal behavior to continue.
The position of the const determines what is immutable, but there is a rule that if the const is placed to the left of the asterisk, then the pointer to the object is immutable, if placed to the right of the asterisk, 10, the pointer cannot be changed. If both sides are there, neither the pointer nor the finger can be changed.
STL iterators are modeled by a pointer, so you can also refer to the pointer usage on a const usage.
One of the things that you have to ask in this article is that the function returns a constant value, although that seems confusing. For example:
Class Rational {...} Const rational operator* (const rational &LHS, const rational &RHS); Rational A, B, C; (A * b) = C; Call Operator=if ((A * b) = c) on the results of a*b ...; In fact, just achieve a comparison, just less write a =
The workaround is to declare the callback value of operator* as const to prevent this meaningless assignment operation.
Summarize:
1) Declaring something as const can help the compiler detect incorrect usage. Const can be applied to objects in any scope, function arguments, function return types, member functions.
2) The compiler enforces bitwise constness, but you should use "Conceptual constants" (conceptual constness) when you write your program.
3) when the const and NON-CONST member functions have a substantially equivalent implementation, making the NON-CONST version call the const version avoids code duplication.
Article 04: Determining that an object has been initialized before it is used
In C + +, object initialization is a bit capricious, and simply put, some object compilers help you initialize by default, and some do not. This, of course, has to do with objects and compilers.
It seems that this is an impossible state, and the best way to do this is to always initialize it before using the object. For built-in types without any members, this must be done manually.
For anything else that is unexpected to the built-in type, the task of initialization is given to the corresponding constructor, so that the rules are much simpler, ensuring that each constructor initializes each member of the object. It is important not to confuse assignment and initialization. Well, in fact, I've never been clear about this concept before ...
Class PhoneNumber {...} Class abentry//abentry = "Address book Entry" {public:abentry (const std::string &name, const std::list< phonenumber> &phones);p rivate:std::string thename;std::list<phonenumber> ThePhones;int numtimesconsulted;};/ /Version One abentry::abentry (const std::string &name, const std::list<phonenumber> &phones) {theName = name; Thephones = phones;numtimesconsulted = 0;}
Write to this, is not relieved, think has completed the initialization? But what has to be said is ... The code inside the Abentry constructor is an assignment, not an initialization.
C + + stipulates that the initialization action of a member variable of an object occurs before entering the constructor body, in fact, there is a better method for Abentry constructor, the use of member initialization column substitution assignment operation:
Version two abentry::abentry (const std::string &name, const std::list<phonenumber> &phones): TheName (name), Thephones (phones), numtimesconsulted (0) (}
Version One first calls the default constructor to initialize members such as Thename, and then assigns them new values. And version Two is the name of the initial value of the thename copy construction, other similar. Obviously version two is more efficient.
The cost of initializing and assigning built-in objects is the same, but in order to be consistent, the same writing is maintained.
Similarly, if you only need the default constructs, you can:
Abentry::abentry (): Thename (), Thephones (), numtimesconsulted (0) {}
If the member variable does not specify the initial value in the initial column of the member, the default constructor is automatically called back, but it is generally stipulated that all member variables are listed in the initial Value column.
The initialization order of member initial columns is the same as the order of member variable declarations, and is independent of the order in which they are placed in the member's initial column, so it is best to place member initializers in the order of member variable declarations.
Also, derived classes are always initialized after their base class is initialized.
For non-local static (Non-local) objects defined in different compilation units, their initialization order is not explicitly defined, so the initialization sequence is prone to a number of problems, and the solution is to replace non-local static objects with local static objects. Well, this is actually the singleton mode (Singleton) that is described in design mode.
Version one: Class filesystem{public:...std::size_t numdisks () const; ...} extern FileSystem Tfs;class directory{public: ... Directory ();..};D Irectory::D irectory () {... std::size_t disks = Tfs.numdisks (); ...} Version two: Class FileSystem {...} FileSystem & TFS () {static FileSystem Fs;return fs;} Class Directory {...} Directory::D irectory () {... std::size_t disks = TFS (). Numdisks (); ...}
Summarize:
1) manual initialization of built-in objects, because C + + does not guarantee that they are initialized.
2) constructors are best used with member initializer columns, rather than using assignment operations within the constructor body. The initial Value column lists the member variables in the same order as they are declared in class.
3) in order to exempt the "initialization Order of cross-compilation units" issue, replace the non-local static object with the local static object.