C++ basic concepts (below)

C++ Basic Concepts
C++ Basic Concepts 1

  1. Similarities and differences between static libraries and dynamic libraries in linux 3
  2. Do you understand dynamic programming 11
  3. Map implementation in STL source code (five requirements of red-black tree) 12
    B+ tree 13
  4. The difference between map and unorder_map (hash_map) 14
  5. How many steps are involved in new an object? Which of the steps can be modified by overloading the new operator 15
  6. How much memory space can malloc apply for at one time? 16
  7. The difference between new and malloc 17
  8. The difference between delete and free19
  9. When must delete[] 20
  10. Static Polymorphism Dynamic Polymorphism 21
  11. Dynamic binding (late binding, runtime binding), static binding (early binding, compile-time binding) 21
  12. Design patterns learned? State machine mode, simple factory, strategy mode, flyweight mode, template mode 1 time 24
  13. The difference between pointers and references: 24
  14. C language code memory layout details 26
  15. The difference between heap and stack in memory 29
  16. User process memory space 30
  17. What are type conversions? (Four types of conversion, each with examples) 30
  18. Memory Alignment Principles 33
  19. Inline functions (talk about the advantages of inline functions and the difference from macro definitions) 35
  20. The usage and difference between typedef and #define 37
  21. The difference between const and macro definition #define 39
  22. Link directive: extern "C" 40
  23. extern与include 44
  24. How to convert between objects, references and pointers in the inheritance mechanism 45
  25. How to realize that only class objects can be allocated dynamically, but class objects cannot be defined 46
  26. Pros and Cons of Templates 47
  27. Template specialization 48
  28. explicit function: Primer P264 50
  29. strcpy function 53
  30. Defects of memcpy 55
  31. Memory overflow, memory leak 56
  32. What are the software for checking memory leaks 58
  33. initialization list 59
  34. Public, protected, private access attributes and inheritance 60
  35. Smart Pointer 61
  36. Virtual and pure virtual functions 64
  37. Why can't the constructor be a virtual function, what is the virtual destructor used for 65
  38. The prototype of pthread_create() function (a thread creation function in Linux environment) is written out 66
  39. The volatile keyword in C 67
  40. Why can the parent class pointer point to the subclass but not vice versa?
  41. How is the size function in the list in stl implemented? Is it traversal or setting a variable to save? Let you achieve, which one do you prefer and why? 69
  42. Subclass a multiple inherits from b and c, and both b and c have virtual functions. How many virtual function tables are there in a? How many virtual function pointers are there? When the virtual functions belonging to b and c are called in turn, how does the virtual function pointer change? 70
  43. Shallow copy or deep copy 72
  44. Difference between copy constructor and assignment operator 76
  45. There are sleep () and usleep () functions in the system call. The usleep () function claims to be at the microsecond level. Do you believe that it can really be so fast? Or can system calls reach microsecond speed? 77
  46. Overloading, Overriding, Hiding 79
  47. this, const member function, mutable type 80
  48. STL Memory Management 81
  49. The difference between static global variables and non-static global variables 83
  50. Write makefile 84
  51. Several possible situations generated by coredump 85
  52. Long and short links in network connections. 86
  53. Synchronous IO and asynchronous IO, blocking and non-blocking 87
  54. Implementing Stacks and Queues 89
  55. big endian little endian 90
  56. What optimizations will the compiler do 92
  57. Call back a member function of an object, but this object may no longer exist, what should I do? 93
  58. Introduce the features of C++11 94
  59. Hard disk copy speed, memory copy speed 95
  60. Gdb debugging, debugging core dump file 96
  61. Can a constructor call a virtual function 98
  62. What happens when dynamic_cast fails? 100
  63. Why can't the destructor throw exception 101

44. Difference between copy constructor and assignment operator

The copy constructor is first a constructor. When it is called, it generates an object, which is initialized by the object passed in as a parameter, and the generated object is generated.
operator=(); is to assign an object (the object already exists) to an original object, so if there is memory allocation in the original object, the memory must be released first, and it is also necessary to check whether the two objects are the same An object, if yes, does nothing.
insert image description here
When using an initialized custom class type object to initialize another newly constructed object, the copy constructor will be called automatically. That is, when an object of a class needs to be copied, the copy constructor will be called. The copy constructor is called in the following situations:
an object is passed into the function body by value,
an object is returned from a function by value, and
an object needs to be initialized by another object.

Using an existing object to construct a non-existing object (that did not exist before construction) is copy construction. Using an existing object to overwrite another existing object is an assignment operation.

When a deep copy is required, the two functions need to be explicitly defined by the programmer at the same time.

45. There are sleep () and usleep () functions in the system call. The usleep () function claims to be at the microsecond level. Do you believe that it can really reach this speed? Or can system calls reach microsecond speed?

insert image description here
insert image description here

46. ​​Overload, override, hide

Overload:

Coverage (for virtual function polymorphism) refers to derived class functions covering base class functions, and only applies to derived class functions. Its characteristics are:

Hiding means that the derived function hides the base class function. Of course, it only works on the derived class function, and its characteristics are different from that of overriding.
In different classes, if the overloading condition is met, it is covered, and if the virtual function coverage condition is met but there is no virtual, it is also hidden.
If the parameter with the same name is the same and virtual, then it is overwritten.

47.this, const member function, mutable type

1. When an object calls a function, it will pass the pointer of the object to initialize this and pass it to the function, so as to distinguish which object the member of the class called inside belongs to. The formal parameter this is a pointer to the class object. Because the static member function is an integral part of the class, but does not belong to any class object, so the static member function does not have this pointer. Virtual functions are also called through this, so static member functions cannot be virtual functions.
2. The type of this of the default member function is a const pointer pointing to the class type. The pointer itself cannot be changed, but the pointed content can be changed, that is, the address of the object cannot be changed, but the members in the object can be changed. Add const after the function to become a const member function. The type of this is a const pointer pointing to a const class type object, and the content in the object cannot be changed. (Non-const member functions cannot be called, because the object may be changed indirectly.)
3. If you want to change the member of the object in the const member function, you need to add the mutable keyword before the member, so that even if the member is in the const member function can also be changed.

Example:
For an example, see

48. STL memory management

Strategy of alloc space allocation
Considering the problem of memory fragmentation that may be caused by small blocks, SGI has designed a two-layer configurator.
When the configuration block exceeds 128 bytes (Bytes), it is considered large enough and the first-level configurator is called;
when the corresponding configuration block is smaller than 128 bytes, it is considered too small and the second-level configurator is called.
The first-level configurator directly uses malloc() and free(). In order to reduce memory fragmentation, the second-level configurator adopts the corresponding Memory pool method.

The management method of the memory pool of the second-level configurator:
(1) free-list: a data structure similar to a single-linked list structure, and each small block in the linked list is not being used by the user (the one being used will be Disconnect the connection with free-list), for the convenience of management, the SGI second layer configurator will actively increase the memory requirement of any small block to a multiple of 8 (for example, if you need 7byte, you will be given 8byte, There are 1byte internal fragments) and maintain 16 free-lists, each managing small blocks of size 8, 16, 24...128bytes.
insert image description here
(A) When the user puts forward the demand (nbyte memory) to the system, the system finds the head pointer corresponding to the linked list from the head array of free-list. If there is no free space in it (the head pointer is empty), the memory pool has no Add it to the remaining memory of free-lis to find it, and apply on the heap if there is no extra space. The details are as follows:
insert image description here
Memory release process:
The memory release process is relatively simple. It accepts two parameters, one is the pointer p pointing to the memory block to be released, and the other indicates the size n of the memory block to be released. The allocator first judges n, if n>128bytes, then hand it over to the first allocator for processing; otherwise, add the memory block to the corresponding free list. (The free list will get bigger and bigger)

49. The difference between static global variables and non-static global variables

1. Static global variables are called: static external variables or static global variables.
2. Non-static global variables are called: external variables or global variables.
3. The difference is: external variables declared with static can only be called by functions in this file, and cannot be called by functions in other files.

Static global variables have the following characteristics:
• The variable allocates memory in the global data area;
• Uninitialized static global variables will be automatically initialized to 0 by the program (the value of the automatic variable is random unless it is explicitly initialized);
• A static global variable is visible throughout the file in which it is declared, but not outside it;

50. Write makefile

51. Several possible situations generated by coredump

There are many reasons for the coredump of the program. Here are some common experiences:
1. The memory access is out of bounds
a) The array access is out of bounds due to the use of wrong subscripts.
b) When searching for a string, rely on the end of the string to determine whether the string is over, but the string does not use the end of the normal character.
c) Use strcpy, strcat, sprintf, strcmp, strcasecmp and other string manipulation functions to read/write the target string. Functions such as strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp should be used to prevent reading and writing out of bounds.

2. The multi-threaded program uses a thread-unsafe function.
The following reentrant functions should be used, they are easily misused:
asctime_r(3c) gethostbyname_r(3n) getservbyname_r(3n)ctermid_r(3s) gethostent_r(3n) getservbyport_r(3n) ctime_r(3c) getlogin_r(3c)getservent_r (3n) fgetgrent_r(3c) getnetbyaddr_r(3n) getspent_r(3c)fgetpwent_r(3c) getnetbyname_r(3n) getspnam_r(3c) fgetspent_r(3c)getnetent_r(3n) gmtime_r(3c) gamma_r(3m) getnetgrent_r(3n) lgamma_ r(3m ) getauclassent_r(3)getprotobyname_r(3n) localtime_r(3c) getauclassnam_r(3) etprotobynumber_r(3n)nis_sperror_r(3n) getauevent_r(3) getprotoent_r(3n) rand_r(3c) getauevnam_r(3)getpwent_r(3c) readd ir_r(3c) getauevnum_r (3) getpwnam_r(3c) strtok_r(3c) getgrent_r(3c)getpwuid_r(3c) tmpnam_r(3s) getgrgid_r(3c) getrpcbyname_r(3n) ttyname_r(3c)getgrnam_r(3c) getrpcbynumber_r(3n) gethostbyaddr_r( 3n) getrpcent_r(3n )

3. The data read and written by multiple threads is not protected by lock.
For global data that will be accessed by multiple threads at the same time, you should pay attention to lock protection, otherwise it will easily cause coredump

4. Illegal pointer
a) Use a null pointer
b) Use pointer conversion at will. A pointer to a piece of memory, unless it is determined that this piece of memory was originally allocated as a certain structure or type, or an array of this structure or type, otherwise it should not be converted into a pointer to this structure or type, but this piece of memory should be The memory is copied into a structure or type of this type, and then the structure or type is accessed. This is because if the start address of this memory is not aligned according to this structure or type, it is easy to core dump due to bus error when accessing it.

5. Stack overflow (repeatedly recursively calling functions without termination conditions)
Do not use large local variables (because local variables are all allocated on the stack), it is easy to cause stack overflow, destroy the stack and heap structure of the system, and cause inexplicable errors .

52. Long and short links in network connections.

HTTP1.1 stipulates to maintain a long connection by default (HTTP persistent connection, which is also translated as a persistent connection). After the data transmission is completed, keep the TCP connection unbroken (no RST packets, no four-way handshake), and wait to continue using this under the same domain name A channel transmits data; the opposite is a short connection.

53. Synchronous IO and asynchronous IO, blocking and non-blocking

When dealing with IO, both blocking and non-blocking are synchronous IO.
Only using a special API is asynchronous IO.
insert image description here
"Blocking" and "non-blocking" and "synchronous" and "asynchronous" cannot be simply understood literally, providing an answer from the perspective of a distributed system.
1. Synchronous and asynchronous
Synchronous and asynchronous focus on the message communication mechanism (synchronous communication/asynchronous communication).
The so-called synchronization means that when a call is issued, the call will not return until the result is obtained . But once the call returns, you get the return value.
In other words, it is up to the caller to actively wait for the result of this call .

Asynchronous is the opposite. After the call is issued, the call returns directly, so no result is returned. In other words, when an asynchronous procedure call is issued, the caller does not get the result immediately. Instead, after the call is issued, the callee notifies the caller through status and notification, or handles the call through a callback function.
a. If the execution component is notified by the state,
the caller needs to check it at regular intervals, which is very inefficient.
Some people who are new to multi-threaded programming always like to use a loop to check the value of a variable. This is actually A very serious mistake.
b. If the method of notification is used,
the efficiency is very high, because the execution component hardly needs to do additional operations.
c. As for the callback function,
it is not much different from the notification.

Typical asynchronous programming models such as Node.js

To give a popular example:
You call the bookstore owner to ask if he has the book "Distributed System". If it is a synchronous communication mechanism, the bookstore owner will say, "Wait a minute, let me check", and then start to check. Wait for the check (it may be 5 seconds, or it may be a day) and tell you the result (return result).
As for the asynchronous communication mechanism, the bookstore owner directly tells you that I will check it, and after checking it, I will call you, and then hang up directly (without returning the result). Then check it out, and he will take the initiative to call you. Here the boss calls back by "calling back".

  1. Blocking and non-blocking
    Blocking and non-blocking focus on the status of the program while waiting for the call result (message, return value).

A blocking call means that the current thread will be suspended before the result of the call is returned. The calling thread will not return until it has the result.
A non-blocking call means that the call will not block the current thread until the result cannot be obtained immediately.

Still the above example,
you call the bookstore owner to ask if there is the book "Distributed System", if you make a blocking call, you will keep "hanging" yourself until you get the result of whether the book is available, if It is a non-blocking call, you don't care if the boss tells you or not, you go to play first, of course, you have to check once in a few minutes to see if the boss has returned the result.
Here blocking and non-blocking have nothing to do with whether it is synchronous or asynchronous. It has nothing to do with how the boss answers your results.

54. Implement stacks and queues

A stack can be implemented with an array.
Queue, implemented with a circular array (reassign a large one when it is full) or a linked list (never overflows)

55. Big endian little endian

Big endian high endian
Little endian small endian
If you regard a number as a string, such as 11223344 as "11223344", the end is a '\0', '11' to '44' occupy a storage unit, then its end The end is obviously 44. The high or low in front means that the end is placed at a high address or a low address. Its placement in memory is very intuitive, as shown in the figure below: There are no standards for
insert image description here
insert image description here
these two byte orders, and there are systems. In use. The byte order used by a given system is called the host byte order, and the following program can be used to output the host byte order. The method is to store the 2-byte value 0x0102 in a short integer variable, and then check its consecutive bytes c[0] (corresponding to address A in the above figure) and c 1 to determine the byte order.
insert image description here

56. What optimizations will the compiler do?

See here for details

57. Call back a member function of an object, but this object may no longer exist, what should I do?

A: Use smart pointers.
M: What smart pointer?
A: shared_ptr.
M: Then how do you know that the object does not exist?
A: Not sure.
M: This is the use of weak_ptr (whether expired() is false, or use_count() > 0) that you didn't know just now. It can judge whether the object still exists.

When the function non-f1 calls f2, it also passes a function f3 (callback function) to f2, and f2 can call f3 to return the result under appropriate conditions.

You go to a store to buy something, and it happens that the item you want is out of stock, so you leave your phone number with the clerk, and after a few days, the store has stock, the clerk calls you, and then you receive a call Then went to the store to pick up the goods. In this example, your phone number is called a callback function, and you leave the call to the clerk to call the registration callback function. When the store has goods later, it is called triggering the event associated with the callback, and the clerk calls you, which is called calling the callback function. You go to the store to pick up the goods is called responding to the callback event.

58. Introduce the features of C++11

1.Auto
2.=default =delete
=default generates a default constructor, although =delete declares this function, it cannot be called in any way, it is generally used for copy constructors and = operators, and can also be used for destructors other functions.
3.nullptr
4.for(auto n:v)
5.Smart pointers:
unique_ptr, shared_ptr, weak_ptr
6.Lambda expression:
represents a callable code unit, which can be understood as an unnamed inline function.
Can appear in a function to indicate that local variables will be used by including them in its capture list [].
The biggest difference from ordinary functions is that in addition to parameters, Lambda functions can also access data in some contexts through capture lists.
1. [var] indicates that the value transfer method captures the variable var;
2. [=] indicates that the value transfer method captures all variables in the parent scope (including this);
3. [&var] indicates that the reference transfer captures the variable var;
4. [& ] means that the reference transfer method captures all variables in the parent scope (including this);
5. [this] means that the value transfer method captures the current this pointer.

1.[=,&a,&b] means to capture variables a and b by reference, and capture all other variables by value; 2.[&,a,this] means to capture variables a
and this by value , the pass-by-reference method captures all other variables.
However, it is worth noting that the capture list does not allow variables to be passed repeatedly. The following examples are typical duplications that lead to compile-time errors. For example:
3. [=, a] here has captured all variables by value transfer, but if a is captured repeatedly, an error will be reported;
4. [&,&this] here & has captured all variables by reference transfer, and then Capturing this is also a repetition.

7. List initialization
8. Regular expressions
9. Static assertion:
static_assert provides a compile-time assertion check. If the assertion is true, nothing happens. If the assertion is false, the compiler will print a special error message.
insert image description here

59. Hard disk copy speed, memory copy speed

The access speed of 70-80MB/s hard disk
and 1GB/s memory is faster than that of hard disk. This is beyond doubt, but how much faster?
The usual saying is: the memory access speed is nanoseconds (10 to the -9 power), and the hard disk access speed is microseconds (10 to the -3 power). Find a slightly scientific test data, as shown in the figure below.
insert image description here
To compare the speed of memory and hard disk, there are two types of comparison:
1. Sequential access: In this case, the memory access speed is only 6~7 of the hard disk access speed times (358.2M / 53.2M = 6.7)
2. Random access: In this case, the memory access speed is more than 100,000 times faster than the hard disk access speed (36.7M / 316 = 113,924)

60. Gdb debugging, debugging core dump file

Common GDB operations
The program above is relatively simple, and the problem can be found directly without additional operations. This is not the case in reality. It is often necessary to perform single-step tracking and set breakpoints to locate the problem smoothly. Some commonly used operations of GDB are listed below.
 Start the program: run
 Set a breakpoint: b line number | function name
 Delete a breakpoint: delete breakpoint number
 Disable a breakpoint: disable breakpoint number
 Enable a breakpoint: enable breakpoint number
 Step through: next also You can abbreviate n
 Single-step tracking: step can also be abbreviated s
 Print variable: print variable name
 Set variable: set var=value
 View variable type: ptype var
 Sequential execution to the end: cont
 Sequential execution to a certain line: util lineno
Print the stack information: bt
start with gdb+file name to enter debugging.
The bt command is highly recommended, especially when the function is deeply nested and the calling relationship is complicated, it can display the call stack of the entire function, and the calling relationship is clear at a glance. In addition, there are two single-step commands above, one is n and the other is s. The main difference is that n will execute the function call as a step, while s will follow up inside the calling function.
The stack information seen by bt is the same as the stack structure, the following call above:

What is Core Dump?
Core means memory, and Dump means throwing it out or heaping it out. When developing and using Unix programs, sometimes the program goes down inexplicably, but there is no prompt (sometimes it will prompt core dumped). This From time to time, you can check whether there is a file in the form of core.process number. This file is generated by the operating system when the program is down and the memory content is thrown out. It can be used as a reference for debugging the program. core dump is also called core
transfer When an exception occurs during the running of the program and the program exits abnormally, the operating system stores the current memory status of the program in a core file, called core dump.

Why is there no core file generated?
Sometimes the program is down, but the core file is not generated. The generation of the core file is related to the environment settings of your current system. You can set it with the following statement, and then run the program to generate the core File.ulimit
-c unlimited
core The location where the core file is generated is generally the same as the path of the running program, and the file name is generally core.process number

After obtaining the core file, you can use the command gdb to search. The first parameter is the name of the application, and the second parameter is the core file.
For example: gdb […]xmsd […]/xmsd_PID1065_SIG11.core

Then enter bt or where to find the location where the error occurred and the corresponding stack information. You can know the function call relationship when an error occurs, and then you can use up or down to view the specific details of the previous and next items. In this way, the problem can be roughly located, and then the source code can be viewed and analyzed.

Can a constructor call a virtual function?

insert image description here
The syntax is acceptable, but you will not get the output you want:
the output when calling the accumulated constructor is not the overridden function.
Actual output:
insert image description here
We know that when constructing an object, the process is as follows:
1) First, a piece of memory (on the heap or on the stack) will be obtained according to the size of the object,
2) The pointer pointing to this piece of memory will be used as this Pointer to call the constructor of the class to initialize this memory.
3) If the object has a parent class, the constructor of the parent class will be called first (and recursively in turn), if there are multiple parent classes (multiple inheritance), the constructor of the parent class will be called in turn, and the this pointer will be adjusted appropriately s position. After calling all the constructors of the parent class, execute your own code.
C++ standard specification. There are clear provisions in Article 12.7.3. This is a special case. In this case, the constructor of the parent class is called when the subclass is constructed, and the virtual member function is called in the constructor of the parent class. Even if the virtual member function is rewritten by the subclass, it cannot Polymorphic behavior is not allowed. That is, at this time, the virtual function of the parent class must be called, not the virtual function rewritten by the subclass.

The reason I want to do this is because when the constructor of the parent class is called, the member variables in the object that belong to the subclass part must not have been initialized, because the code in the subclass constructor has not been executed. If polymorphic behavior is allowed at this time, that is, the virtual function of the subclass is called through the constructor of the parent class, and errors may occur when this virtual function wants to access data members belonging to the subclass.
The same principle also applies to the destructor. Once the derived class destructor starts to execute, the derived class member variables in the object will have undetermined values, so C++ treats them as if they no longer exist. After entering the base class destructor, the object becomes a base class object, and any part of C++ including virtual functions, dynamic_cast, etc. treats it that way.
Virtual functions called during base class construction and destructor calls do not descend into derived classes. See article 9 of effective c++ for details.

62. What happens when the dynamic_cast conversion fails?

A base class object pointer (or reference) cast to the inherited class pointer pair
pointer, returns NULL.
For references, a bad_cast exception is thrown.

63. Why can't destructors throw exceptions?

more effective c++ puts forward two reasons (the reason why the destructor cannot throw an exception):
1) If the destructor throws an exception, the program after the exception point will not be executed, if the destructor executes something after the exception point Some necessary actions, such as releasing certain resources, will not be executed, which will cause problems such as resource leaks.
2) Usually when an exception occurs, the C++ mechanism will call the destructor of the constructed object to release resources. At this time, if the destructor itself also throws an exception, the previous exception has not been processed, and there is a new exception, which will cause Program crash problem.

The C++ exception handling model is responsible for clearing objects that have become invalid due to exceptions (that is, the object has exceeded its original scope), and releasing the resources originally allocated by the object, which is to call the destructor of these objects To complete the task of releasing resources, so in this sense, the destructor has become a part of exception handling.
The above discussion of the C++ exception handling model actually has a premise that no exception should be thrown in the destructor. Just imagine, if an exception occurs in the object, the exception handling module is now responsible for releasing the resources of the object and calling the destructor of the object in order to maintain the consistency of the system object data and avoid resource leakage. , then who will guarantee the resource release of this object? And who will handle this new exception? Don't forget that the previous exception has not been processed yet, so this is caught in a contradiction. Or in infinite recursive nesting.

3.2 So what should we do when it is impossible to guarantee that no exception will occur in the destructor?
In fact, there are still good ways to solve it. That is to completely encapsulate the exception inside the destructor, and never let the exception be thrown out of the function (or use the smart pointer to treat the resources used as the original object). This is a very simple and very effective method.
~ClassName()
{ try{ do_something(); } catch(){ //You can do nothing here, just ensure that the exception thrown by the program in the catch block will not be thrown out of the destructor. } }





Guess you like

Origin blog.csdn.net/fjj2397194209/article/details/131351707