C++ Chapter 1. Accustoming Yourself to C++

来源:互联网 发布:stp指定端口选举过程 编辑:程序博客网 时间:2024/06/01 09:27

1. For an object, the definition is where compilers set aside memory for the object. For a function or a function template, the definition provides the code body. For a class or a class template, the definition lists the members of the class or template

2.

Widget w3 = w2;                           // invoke copy constructor!

Fortunately, copy construction is easy to distinguish from copy assignment. If a new object is being defined (such as w3 in the statement above), a constructor has to be called; it can't be an assignment. If no new object is being defined (such as in the "w1 = w2" statement above), no constructor can be involved, so it's an assignment.

Pass-by-value means "call the copy constructor." 

3. Usually, C++ requires that you provide a definition for anything you use, but class-specific constants that are static and of integral type (e.g., integers, chars, bools) are an exception. As long as you don't take their address, you can declare them and use them without providing a definition.

in-class initialization is allowed only for integral types and only for constants.
4.
template<typename T>                               // because we don'tinline void callWithMax(const T& a, const T& b)    // know what T is, we{                                                  // pass by reference-to-  f(a > b ? a : b);                                }
reference 确保不会make copy, 不用call copy constructor, const确保不会修改原值。
5.

STL iterators are modeled on pointers, so an iterator acts much like a T* pointer. Declaring an iterator const is like declaring a pointer const (i.e., declaring a T* const pointer): the iterator isn't allowed to point to something different, but the thing it points to may be modified. If you want an iterator that points to something that can't be modified (i.e., the STL analogue of a const T* pointer), you want a const_iterator:

6.The purpose of const on member functions is to identify which member functions may be invoked on const objects. Such member functions are important for two reasons. First, they make the interface of a class easier to understand. It's important to know which functions may modify an object and which may not. Second, they make it possible to work with const objects. That's a critical aspect of writing efficient code, because, as Item 20 explains, one of the fundamental ways to improve a C++ program's performance is to pass objects by reference-to-const. That technique is viable only if there are const member functions with which to manipulate the resulting const-qualified objects.

That's because it's never legal to modify the return value of a function that returns a built-in type(You have to use reference or pointer)

7. Initialization List is more efficient than assignment-based version because The assignment-based version first called default constructors to initialize theName, theAddress, and thePhones, then promptly assigned new values on top of the default-constructed ones. All the work performed in those default constructions was therefore wasted. The member initialization list approach avoids that problem, because the arguments in the initialization list are used as constructor arguments for the various data members. In this case, theName is copy-constructed from name, theAddress is copy-constructed from address, and thePhones is copy-constructed from phones. For most types, a single call to a copy constructor is more efficient — sometimes much more efficient — than a call to the default constructor followed by a call to the copy assignment operator.

If in the initialization list, there is no value in the argument, then it will call the default constructor.

8.One aspect of C++ that isn't fickle is the order in which an object's data is initialized. This order is always the same: base classes are initialized before derived classes (see also Item 12), and within a class, data members are initialized in the order in which they are declared. In ABEntry, for example, theName will always be initialized first, theAddress second, thePhones third, and numTimesConsulted last. This is true even if they are listed in a different order on the member initialization list (something that's unfortunately legal). 

9.

A static object is one that exists from the time it's constructed until the end of the program. Stack and heap-based objects are thus excluded. Included are global objects, objects defined at namespace scope, objects declared static inside classes, objects declared static inside functions, and objects declared static at file scope. Static objects inside functions are known as local static objects (because they're local to a function), and the other kinds of static objects are known as non-local static objects. Static objects are automatically destroyed when the program exits, i.e., their destructors are automatically called when main finishes executing.

A translation unit is the source code giving rise to a single object file. It's basically a single source file, plus all of its #include files.

The problem we're concerned with, then, involves at least two separately compiled source files, each of which contains at least one non-local static object (i.e., an object that's global, at namespace scope, or static in a class or at file scope). And the actual problem is this: if initialization of a non-local static object in one translation unit uses a non-local static object in a different translation unit, the object it uses could be uninitialized, because the relative order of initialization of non-local static objects defined in different translation units is undefined.

This approach is founded on C++'s guarantee that local static objects are initialized when the object's definition is first encountered during a call to that function. So if you replace direct accesses to non-local static objects with calls to functions that return references to local static objects, you're guaranteed that the references you get back will refer to initialized objects. As a bonus, if you never call a function emulating a non-local static object, you never incur the cost of constructing and destructing the object, something that can't be said for true non-local static objects.

10.

Things to Remember

  • Manually initialize objects of built-in type, because C++ only sometimes initializes them itself.

  • In a constructor, prefer use of the member initialization list to assignment inside the body of the constructor. List data members in the initialization list in the same order they're declared in the class.

  • Avoid initialization order problems across translation units by replacing non-local static objects with local static objects.

2.1 pass-by-value is generally more efficient than pass-by-reference for built-in (i.e., C-like) types

2.2 Prefer compiler to preprocessor

when use

#define ASPECT_RATIO 1.653

the symbolic name ASPECT_RATIO may never be seen by compilers; it may be removed by the preprocessor before the source code ever gets to a compiler. As a result, the name ASPECT_RATIO may not get entered into the symbol table. This can be confusing if you get an error during compilation involving the use of the constant, because the error message may refer to 1.653, not ASPECT_RATIO.



2.3

Two ways to initialize a static const variable in class

1) 

private:

static const int aa = 5;

2)

Class Solution

{

private:

static const int aa;

};

const int Solution::aa = 5;

Both way works fine, but when we need to use aa as an const in array size, only way 1 works.

There is another way to create a const for array size: enum hack

class GamePlayer {private:  enum { NumTurns = 5 };        // "the enum hack" — makes                                // NumTurns a symbolic name for 5  int scores[NumTurns];         // fine  ...};
it's legal to take the address of a const, but it's not legal to take the address of an enum, and it's typically not legal to take the address of a#define, either. If you don't want to let people get a pointer or reference to one of your integral constants, an enum is a good way to enforce that constraint. 


 'const int' VS 'static const int' VS 'static int?'(inside a class)

In such a context, static declares that there will be only 1 such class-wide data member; as opposed to there being 1 per-instance (inside every object of the class). The const declares that this variable will receive a value only during its construction.

Inside a member function of a class (or for that matter, any function), static means that it's non-automatic; that is, that its value survives returning from the function (also that it can have a value prior to ever entering it, too). It also means that multiple threads of execution through such a routine can contend over access to the variable.

we can only initialize const int in initialization list(also reference variable, because reference can't be assign), while we can initialize static const int in declaration or outside out class by definition
Static 
variable
because count is a static variable, the line "static int count = 0;" will only be executed once. Whenever the function is called, count will have the last value assigned to it.
If in class, it can only be initialized outside a class using:
int Solution::s_num = 5;

class Solution
{
public:
Solution(int s):num_(s)
{
}
static int s_num;
static const int num = 5;
int a[num];
//const int _num = 5; error! only static const integral data member can be initialized within a class
//static const int num = 5; correct!
const int num_;
};
int Solution::s_num = 5
总结:non-static用initialization list初始化, static 在外面初始化


Static class function:
Can be access with a instance of class, can only access static member variable.

2.4  member functions differing only in their constness can be overloaded, 

class TextBlock {public:  ...  const char& operator[](std::size_t position) const   // operator[] for  { return text[position]; }                           // const objects  char& operator[](std::size_t position)               // operator[] for  { return text[position]; }                           // non-const objectsprivate:   std::string text;};
when the two version of function have most part in common, in order to avoid duplication, we can call const function from non-const version using the code below(not vice versa).
class TextBlock {public:  ...  const char& operator[](std::size_t position) const     // same as before  {    ...    ...    ...    return text[position];  }  char& operator[](std::size_t position)         // now just calls const op[]  {    return      const_cast<char&>(                         // cast away const on                                                 // op[]'s return type;        static_cast<const TextBlock&>(*this)     // add const to *this's type;          [position]                            // call const version of op[]      );  }...};

TextBlock's operator[]s can be used like this:

TextBlock tb("Hello");std::cout << tb[0];                   // calls non-const                                            // TextBlock::operator[]const TextBlock ctb("World");std::cout << ctb[0];                  // calls const TextBlock::operator[]

const member function:
Can't modify any of the object's data members (excluding those that are static and mutable),
these data members may
mutable std::size_t textLength;
mutable bool lengthIsValid; // always be modified, even in}; // const member functions
2.5
an array (from the C part of C++) isn't necessarily guaranteed to have its contents initialized, but a vector (from the STL part of C++) is.
2.6

the extern keyword is used to tell the compiler that a data object is declared in a different *.cpp or *.c file (code unit). Its required for data objects but optional for function declarations. For example, you have two *.cpp files named A.cpp and B.cpp. B.cpp has a global int that needs to be used in A.cpp. But when a variable or function is defined with keyword "static", it can't be extern to other file, it can only be used in current file.

  1. // A.cpp
  2. #include <iostream>
  3. // other includes here
  4. ...
  5. extern int hours; // this is declared globally in B.cpp
  6. int foo()
  7. {
  8. hours = 1;
  9. }
  1. // B.cpp
  2. #include <iostream>
  3. // other includes here
  4. ...
  5. int hours; // here we declare the object WITHOUT extern
  6. extern void foo(); // extern is optional on this line
  7. int main()
  8. {
  9. foo();
  10. }