Interview summary: Goose factory Linux background development interview written examination C + + knowledge points reference notes


The article is continuously updated every week. Your “three links” are the greatest affirmation to me. WeChat can search the public for the first time to read the official account of “backend Technology School” (usually one to two updates earlier than blogs).

The article was sorted out from Tencent’s notes of his written interview. When sorting it out, he reviewed it again. He was busy in the middle and sorted it out intermittently for half a month. It is mainly for the C + + background development positions interviewed, covering most of the technical points related to C + + that may be asked, which can be used as a reference for interview technology.

At the end of this paper, the acquisition method of learning resources for the knowledge points of this paper is provided, which can be obtained by the students themselves.

This note is a summary of basic C + + knowledge points. It does not elaborate too much on the system architecture of background development and the design of distributed background services, as well as the new features of C + + 11. These written examination interviews will also be asked, but they are not within the scope of this discussion. You can pay attention to the back of the column and supplement them if you have the opportunity.

Why is a destructor a virtual function?

The base class pointer can point to the object of the derived class (polymorphism). If the pointer is deleted, delete []p; The destructor of the derived class pointed to by the pointer will be called, and the destructor of the derived class will automatically call the destructor of the base class, so that the object of the whole derived class will be completely released. If the destructor is not declared as a virtual function, the compiler implements static binding. When deleting the base class pointer, it will only call the destructor of the base class instead of the destructor of the derived class, resulting in incomplete destructor of the derived class object. Therefore, it is necessary to declare destructors as virtual functions.

GDB debug command

What is the difference between step and next?

When the current line has a function call, next will execute directly to the next sentence, and step will enter the function

view memory

(GDB) P & A / / print variable address

GDB) x 0xbffff543 / / view variables in memory cells

0xbffff543: 0x12345678

(GDB) x / 4xb 0xbffff543 / / view the values of four memory cell variables in a single byte

0xbffff543: 0x78 0x56 0x34 0x12

Multithreading debugging

(GDB) info threads: see the relevant information of each thread of GDB’s currently debugged program.

(GDB) thread threadno: switch the current thread to the thread specified by threadno

Break filename: linenum thread all set breakpoints on the corresponding lines of all threads. Note that if the main thread does not execute to this line and the all stop mode is started, the main thread will switch to N or S

Set scheduler locking off | onstep is off by default, and other threads executing s or C also execute synchronously. On, only current execution. Step, only the current thread executes

Show scheduler locking displays the current mode

Thread apply all command each thread executes a consent command, such as BT. Or thread apply 1 3 BT, that is, threads 1 and 3 execute BT.

View call stack


(GDB) brief information of F 1 frame

(GDB) info F 1 frame details


b test.cpp:11

b test.cpp:main

GDB attach debugging method:

GDB – > file XXXX – > attach PID – > the process stops at this time – > C continues to run

Debugging with parameters

Enter the parameter command set args, followed by the parameters to be used by the program. Note that there is no program name, but directly add parameters, such as:

(gdb)set args -l a -C abc

List command

List linenum displays the programs around line linenum of the program

List function displays the source program of the function named function

Function of static keyword

Hard and soft links

Ln – s source file, target file, LN – S / / home / good / linkname link root directory / to / home / good / linkname

1. The soft link is “LN – s source file target file”. It will only generate a file image at the selected location and will not occupy disk space. It is similar to the shortcut of windows.

2. Hard link ln source file target file. Without the parameter – s, a file with the same size as the source file will be generated at the selected location. Whether it is soft link or hard link, the file will keep changing synchronously.

Function pointer

Function pointer int (* func) (int, int)

Function pointer array int (* funcarry [10]) (int, int)

const int* p; Pointer to const int

int const* p; ditto

int* const p; const pointer

Design pattern

Singleton mode

Observer mode (also known as publish subscribe mode)

There are three factory modes: simple factory mode, factory method mode and abstract factory mode

Why use factory mode? The reason is to isolate the object creation process from the upper users; Or the process of object creation is complex,

It is not easy for users to master; Or object creation should meet certain conditions, which are business requirements or system constraints

, there is no need for upper level users to master it and increase the difficulty of others’ development. So, by this time, we should be clear that whether it is the factory model,

Or the opening and closing principle mentioned by the comrades in arms above is to isolate some complex processes so that these complex processes are not exposed,

If these processes are exposed, it will add trouble to users, which is the so-called teamwork.

data structure

Various sorting algorithms

Heap sort

Key: 1. The initial heap building is adjusted from the last non leaf node. 2. The filtering is adjusted from the vertex down

Easy to understand fast platoon

Binary tree theorem

Degree = 2 nodes = leaf nodes – 1

Proof: number of branches = number of nodes – 1, N00 +n11 + N2 * 2 = N0 + N1 + n2-1 (N0 represents the number of nodes with 0, and so on)


pthread_mutex_t m_mutex;
pthread_ mutex_ init(&m_ Mutex (null) is equivalent to pthread_ mutex_ t mutex = PTHREAD_ MUTEX_ INITIALIZER
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
bool g_flag = false;
void* t1(void* arg)
  cout << "create t1 thread success" << endl;
  g_flag = true;

void* t2(void* arg)
  cout << "create t2 thread success" << endl;
  g_flag = false;

int main(int argc, char* argv[])
  pthread_t tid1, tid2;
  pthread_create(&tid1, NULL, t1, NULL);
  pthread_create(&tid2, NULL, t2, NULL);
  pthread_join(tid1, NULL);
  pthread_join(tid2, NULL);

Size conversion

#define BigLittleSwap32(A) ((((uint32)(A) & 0xff000000) >> 24) | \
                     (((uint32)(A) & 0x00ff0000) >> 8) | \
                     (((uint32)(A) & 0x0000ff00) << 8) | \
                     (((uint32)(A) & 0x000000ff) << 24))

IO multiplexing

Why does IO multiplexing work with non blocking IO

Set non blockingio fcntl(sockfd, F_SETFL, O_NONBLOCK);


int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

void FD_CLR(int fd, fd_set *set);

int FD_ISSET(int fd, fd_set *set);

void FD_SET(int fd, fd_set *set);

void FD_ZERO(fd_set *set);

fd_set rdfds;
struct timeval tv;
int ret;
FD_SET(socket, &rdfds);
tv.tv_sec = 1;
tv.tv_uses = 500;
ret = select (socket + 1, %rdfds, NULL, NULL, &tv);
if(ret < 0) perror (“select”);
else if (ret = = 0) printf(“time out”);
    printf(“ret = %d/n”,ret);
    if(FD_ISSET(socket, &rdfds)){
      /*Read data in socket handle*/
}Note that the first parameter of the select function is the maximum value of all handles added to the collection, and the value should be added with 1. For example, we created three handles;

Poll implementation

The implementation of poll is very similar to that of select, except that the way to describe the FD set is different. Poll uses the pollfd structure instead of the FD of select_ The set structure is similar to the others. Polling is also used to manage multiple descriptors, which is processed according to the descriptor status, but poll has no limit on the maximum number of file descriptors. Poll and select also have a disadvantage that the array containing a large number of file descriptors is copied between the user state and the address space of the kernel as a whole. Regardless of whether these file descriptors are ready or not, its overhead increases linearly with the increase of the number of file descriptors.

Epoll principle…

#include <sys/epoll.h>
int epoll_create(int size);

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

Epoll operates on file descriptors in two modes: LT (level trigger) and ET (edge trigger). LT mode is the default mode. The differences between LT mode and et mode are as follows:

LT mode: when epoll_ Wait detects the occurrence of a descriptor event and notifies the application of this event. The application may not process the event immediately. Next call epoll_ When you wait, the application responds again and notifies you of this event.

Et mode: when epoll_ Wait detects the occurrence of a descriptor event and notifies the application of this event, which must be handled immediately. If not, epoll will be called next time_ When waiting, the application will not respond again and notify this event.

Et mode reduces the number of epoll events repeatedly triggered to a great extent, so the efficiency is higher than LT mode. When epoll works in et mode,

Non blocking sockets must be used to avoid starving the task of processing multiple file descriptors due to blocking read / write operations of one file handle.

Under epoll et model, why does each epollin event bring an epollout event…

UDP socket



#include <sys/socket.h> 

ssize_t sendto(int sockfd, void *buff, size_t nbytes, int flags,  const struct sockaddr *destaddr, socklen_t addrlen); 

ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,  struct sockaddr *addr, socklen_t *addrlen); 

network sockets

UDP principle and socket

UDP server:


bind(sockListener,(struct sockaddr*)&addrListener,sizeof(addrListener))

nMsgLen=recvfrom(sockListener,szBuf,1024,0,(struct sockaddr*)&addrClient,&addrLen)   

UDP client

bind(sockClient,(struct sockaddr*)&addrLocal,sizeof(addrLocal))
cout<<"you can type in sentences any time"<<endl;
bind(sockClient,(struct sockaddr*)&addrLocal,sizeof(addrLocal))
cout<<"you can type in sentences any time"<<endl;
'; cout<<"read:"<<szRecv<<endl; } }

Use the connect function in UDP to become a connected socket

The connected UDP socket has the following changes compared with the unconnected UDP socket:

  1. The destination IP address and port number cannot be specified for the output operation (because it has been specified when calling the connect function), that is, the SendTo function cannot be used, but the write or send function. The content written to the connected UDP socket will be automatically sent to the protocol address specified by connect;
  2. Instead of using the recvfrom function to know the sender of the datagram, use the read, recv, or recvmsg functions. On a connected UDP socket, the only datagrams returned by the kernel for input operations are those from the protocol address specified by the connect function. The destination is the local protocol address of the connected UDP socket. Datagrams whose origin is not the protocol address to which the socket was previously connected will not be delivered to the socket. That is, only when the protocol address of the origin matches the address specified by connect can the datagram be transmitted to the socket. In this way, the connected UDP socket can only exchange datagrams with one peer;
  3. Asynchronous errors caused by connected UDP sockets will be returned to their processes, while unconnected UDP sockets will not receive any asynchronous errors;

TCP socket


listenfd = socket(AF_INET , SOCK_STREAM , 0)

bind(listenfd , (struct sockaddr*)&servaddr , sizeof(servaddr))

listen(listenfd , LISTENQ)

connfd = accept(listenfd , (struct sockaddr *)&cliaddr , &clilen))

n = read(connfd , buff , MAX_LINE)

write(connfd , buff , n)


sockfd = socket(AF_INET , SOCK_STREAM , 0)

connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr))

write(sockfd , sendline , strlen(sendline))

Interview summary: Goose factory Linux background development interview written examination C + + knowledge points reference notes

IP fragmentation and reorganization

Reference 1

Reference 2

MTU refers to the Ethernet MTU of 1500. You can use the netstat – I command to view this value. If the IP layer has packets to transmit, and the packet length exceeds the MTU,

Then the IP layer needs to fragment the data packet so that the length of each piece is less than or equal to MTU.

Suppose we want to transmit a UDP packet. The MTU of Ethernet is 1500 bytes. Generally, the IP header is 20 bytes and the UDP header is 8 bytes. The payload of the data

Some reserved bytes are 1500-20-8 = 1472 bytes. If the data part is larger than 1472 bytes, fragmentation will occur,

The offset is in 8byte

Whether the same partition is marked by ID and the position in the message is marked by offset. Each incomplete ID message has a waiting timer. When it is discarded, the IP layer does not guarantee delivery,

If the upper layer is lost, handle it yourself. Refer to RFC 791

IP message length unit formula

4 byte unit – header length unit 1 byte unit – total length unit 8 byte unit – slice offset unit

STL container

Vector and list

1. Vector data structure

Like an array, a vector has a continuous memory space and the starting address remains unchanged.

Therefore, it can carry out random access efficiently, and the time complexity is O (1);

However, because the memory space is continuous, the insertion and deletion operations will cause the copy of memory blocks, and the time complexity is O (n).

In addition, when the memory space in the array is insufficient, a new memory space will be applied for and a memory copy will be made.

2. List data structure

List is implemented by a two-way linked list, so the memory space is discontinuous.

The data can only be accessed through pointers, so the random access of list is very inefficient, and the time complexity is O (n);

However, due to the characteristics of linked list, it can insert and delete efficiently.

Vector dynamic memory allocation

This problem is actually very simple. When calling push_ Back, if the current capacity cannot be put into the experience element (capacity = size), then vector will re apply for a piece of memory, copy the elements in the previous memory to the new memory, and then push_ The element of back is copied to the new memory. Finally, the original vector is destructed and the original memory is released. Therefore, the efficiency of this process is extremely low. In order to avoid frequent memory allocation, the memory applied for by C + + will increase exponentially every time. For example, it was 4 before, and it will be 8 after re application, and so on. Of course, it does not necessarily increase exponentially. For example, in my compiler environment, the measured increase is 0.5 times, which was 4 before and 6 after re application


preprocessor directives

#Pragma once prevents repeated references to header files

One byte alignment

#pragma pack(push, 1)

#pragma pack(pop)

Class object oriented

Class inheritance

class LayerManager : public ILayerManager{};

Covering virtual function mechanism

In some cases, you want to override the virtual function mechanism and force function calls to use a specific version of the virtual function

In this example, you can use the scope operator:

Item_base *baseP = &derived;

// calls version from the base class regardless of the dynamic type

of baseP

double d = baseP->Item_base::net_price(42);

This code forces net_ The price call is determined to be item_ The version defined in the base is called

Will be determined at compile time.

Only code in member functions should override the virtual function mechanism with scope operators.

Why do you want to override the virtual function mechanism? The most common reason is to derive class virtual function call bases

The version in the class. In this case, the base class version can complete the common tasks of all types in the inheritance hierarchy,

Each derived type only adds its own special work. For example, you can define a camera class hierarchy with virtual operations. Display in camera class

Function can display all public information, and derived classes (such as perspectivecamera) may need to be explicit

Public information needs to display its own unique information. You can explicitly call the camera version to display the public

Information, rather than copying camera operations in the display implementation of perspective camera.

In this case, you already know exactly which instance to call, so you don’t need to go through the virtual function mechanism.

When a derived class virtual function calls the base class version, the scope operator must be explicitly used.

If a derived class function ignores doing so, the function call is determined and executed at run time

And will be a self call, resulting in infinite recursion.

Name conflict and inheritance

Although a base class member can be accessed directly as if it were a derived class member, the member retains it

Base class membership for. Generally, we don’t care which actual class contains members, usually only in the base class and pie

Only when students share the same name.

A derived class member with the same name as the base class member blocks direct access to the base class member.

struct Base
    Base(): mem(0) { }
    int mem;

struct Derived : Base 
    Derived(int i): mem(i) { } // initializes Derived::mem
    int get_mem() { return mem; } // returns Derived::mem
    int mem; // hides mem in the base

get_ The reference to MEM in MEM is determined to use the name in derived. If you write the following code:
Derived d(42);
cout << d.get_mem() << endl; // prints 42

The output will be 42.

Access masked members using scope operators

You can use the scope operator to access masked base class members:

struct Derived : Base 
    int get_base_mem() { return Base::mem; }

The scope operator instructs the compiler to look for MEM in base.

When designing derived classes, it is best to avoid having the same name as the data member of the base class whenever possible

What is the difference between overloading, overriding and hiding class member functions?

a. Characteristics of overloaded member functions:

(1) The same scope (in the same class);

(2) Same function name;

(3) Different parameters;

(4) The virtual keyword is optional.

b. Override means that derived class functions override base class functions, which is characterized by:

(1) Different ranges (in derived and base classes respectively);

(2) Same function name;

(3) The parameters are the same;

(4) Base class functions must have the virtual keyword.

c. “Hidden” means that the function of the derived class masks the base class function with the same name. The rules are as follows:

(1) If the function of the derived class has the same name as the function of the base class, but the parameters are different. At this time, the functions of the base class will be hidden whether there is the virtual keyword or not (note that it should not be confused with overloading, just the same name).

(2) If the function of the derived class has the same name as the function of the base class and the parameters are the same, but the base class function does not have the virtual keyword. At this point, the functions of the base class are hidden (be careful not to confuse them with overrides)

Pure virtual function

class Disc_item : public Item_base 

    double net_price(std::size_t) const = 0;

A class that contains (or inherits) one or more pure virtual functions is an abstract base class. Except for

It is part of the object of the derived class of the abstract base class. You can’t even create the abstract type disc_ The object of the item.

Template programming

Function template

template <typename T> 
int compare(const T &v1, const T &v2)
    if (v1 < v2) return -1;
    if (v2 < v1) return 1;
    return 0;

Use compare (1, 2)

Class template

template <class Type> class Queue 



    Queue (); // default constructor
    Type &front (); // return element from head of Queue
    const Type &front () const;
    void push (const Type &); // add element to back of Queue
    void pop(); // remove element from head of Queue
    bool empty() const; // true if no elements in the Queue
    // ...

Use queue < int > Qi;

operators overloading

Output operator

The output operator is usually a non member function defined as a friend of the class

friend ostream& operator<<(ostream& out, const Sales_item& s)
    out << s.isbn << "\t" << s.units_sold << "\t"
    << s.revenue << "\t" << s.avg_price();
    return out;

Arithmetic and relational operations

Arithmetic and relational operators are defined as non member functions

To be consistent with built-in operators, addition returns an R-value instead of a reference.

Sales_item operator+(const Sales_item& lhs, const Sales_item& rhs)


    Sales_item ret(lhs); // copy lhs into a local object that we'll
    ret += rhs; // add in the contents of rhs
    return ret; // return ret by value

int operator<(const TableIndex2D& right) const;

friend bool operator== (const UEContext& info1,const UEContext& info2) const
    if(info1.ContextID != info2.ContextID) return false;
    return true;

friend bool operator!= (const UEContext& info1,const UEContext& info2) const
    return !(info1 == info2);

Copy control

It includes a copy constructor, an assignment operator, a destructor, and a pair of addressing operators

If you write this:class Empty{};

It’s the same as you wrote:

class Empty 
    Empty();            //  Default constructor 
    Empty(const Empty& rhs);    //  copy constructor 
    ~Empty();            //  Destructor - Yes No
             //For virtual functions, see the following description
     Empty& operator=(const Empty& rhs);  //  Assignment Operators 
     Empty* operator&();       //  address-of operator 
     const Empty* operator&() const;

Empty(const Empty& rhs)
    a = rhs.a

The class assignment operator must be a member of the class so that the compiler can know whether to synthesize one. The assignment must return a reference to * this.

In general, assignment operators and compound assignment operators should return references to operators

Guti& Guti::operator=( const Guti& rhs )
  mtmsi_m = rhs.mtmsi_m;
  mmeCode_m = rhs.mmeCode_m;
  mmeGid_m = rhs.mmeGid_m;
  plmnId_m = rhs.plmnId_m;
  return *this;

Note that check the assignment to yourself
c& c::operator=(const c& rhs)
 //Check the assignment to yourself
 if (this == &rhs) return *this;

Constructor initializer

The only chance to initialize const objects and reference objects. P389 C++ Primer 5th



RTP protocols rfc1889 and rfc3550 g711 pcmu


Linux Basics

Array of Linux shells:…

Linux expr command:…

Variable type in shell: local, global, export keyword:…

Linux let command:…

VIM modify tab to 4 spaces and write Python:…

Several methods for Python to judge whether a file exists:…

Python — file operation delete a line:…

Several operations of Python 3 dictionary traversal:…


Command name: Chmod

Execution Authority: all users

Function Description: change file or directory permissions

Syntax: the first method Chmod [{ugoa} {+ – =} {RWX}] [file or directory]

Remarks: u: owner G: group O: others a: owner

                  +: increase permissions for users -: decrease permissions for users =: grant permissions to users

                  r: W: execute permission 

      The second method Chmod - R [mode = 421] [file or directory] ← (this method is used more)

       Remarks: R: 4 W: 2 x: 1

                  R is the read permission, which can be represented by 4,

                  W is the write permission, which can be represented by 2,

                  X is the execution permission, which can be represented by 1.

New operation

Dynamically allocate array int * PIA = New Int [10]// array of 10 uninitialized ints

Release the allocated array delete [] PIA;

New array

int *arr = new int[1024]
delte [] a
#New object on heap
class MyClass
    MyClass(int a) {};
    int empty() {return 0;};

MyClass *p = new MyClass(1);
delete p;

#Allocating objects on the stack
MyClass test(1);

Placement new

Distinguish the following operation symbols:

New operator – common new keyword

Operator new – only apply for memory and return void*

Placement new – call the constructor to initialize the class in the specified memory

New [] operator – if it is a class object, it will apply for 4 bytes of memory in the head to save the number of objects

Delve deeper into new and delete…

When we use the keyword new to dynamically create an object a on the heap, such as a * P = new a (), it actually does three things:

Apply for a piece of memory space on the heap (enough data to accommodate the size of object a) (operator new)

Call constructor (call a’s constructor (if a has one)) (placement new)

Returns the correct pointer

Of course, if we create variables of simple type, the second step will be omitted.

The same is true when we delete, for example, when we delete P, the behavior is as follows:

Locate the memory space pointed to by the pointer P, and then call its own destructor according to its type (not used for built-in types)

Then free its memory space (mark this memory space as available and return it to the operating system)

Mark pointer as invalid (point to null)…

void* p=::operator new (sizeof(Buffer));  // Create a piece of memory; A colon indicates global new
Buffer* bp= start_ cast<Buffer*>(p);  // Replace the pointer
Buffer* buf3=new(bp) Buffer(128);   // Point the BP pointer to the memory lease buf3,
buf3->~Buffer();  // Here is the function to display the call
::operator delete(p);

Place new construction object array

Interview summary: Goose factory Linux background development interview written examination C + + knowledge points reference notes

Allocate class memory on the stack:…

What is the difference between new and malloc

b. The biggest difference between new and malloc: new will call the constructor of the class, malloc will not;

c. Delete and free are the same; New / delete is the operator, malloc / free function. Therefore, the efficiency of new / delete should be higher.

Summary of Linux IPC mechanism

The Conduit

#include <unistd.h>

Anonymous pipes: int pipe (int pipes [2])

Named pipeline: int mkfifo (const char * pathname, mode)_ t mode)

Message queue

#include <sys/msg.h>

int msgget(key_ T key, int msgflg) // create

int msgctl(int msqid, int cmd, struct msqid_ DS * buf) // set / get the attribute value of the message queue

int msgsnd(int msqid, const void *msgp, size_ T msgsz, int msgflg) // send a message to the message queue (add to the end)

ssize_ t msgrcv(int msqid, void *msgp, size_ T msgsz, long msgtyp, int msgflg) // receive the message

Shared memory

#include <sys/shm.h>

int shmget(key_ t key, size_ T size, int shmflg) // create a shared memory space

int shmctl(int shmid, int cmd, struct shmid_ DS * buf) // operations on shared memory processes, including reading / setting status and deleting

Void * shmat (int shmid, const void * shmaddr, int shmflg) // mount the shared memory space into the process

Int shmdt (const void * shmaddr) // separate the process from the shared memory space * * (* * * * only it is no longer associated with the shared memory and does not delete the shared memory * * * *)**



Implement strcpy manually

char *strcpy(char *strDest, const char *strSrc)
    if ( strDest == NULL || strSrc == NULL)
    return NULL ;
    if ( strDest == strSrc)
    return strDest ;
    char *tempptr = strDest ;
    while( (*strDest++ = *strSrc++) != ‘/0’)
    return tempptr ;

C + + object memory layout

This part of the details can refer to the in-depth exploration of the C + + object model

Virtual function polymorphism mechanism

Virtual member functions are accessed through virtual table pointers. The access to ordinary member functions is different from virtual member functions. The details are as follows:

The call of virtual member function normalize() is actually converted to:

Interview summary: Goose factory Linux background development interview written examination C + + knowledge points reference notes

There are also differences in function pointers. The first one below is an ordinary function pointer or static member function. The second is the non static member function pointer.
Interview summary: Goose factory Linux background development interview written examination C + + knowledge points reference notes

Object memory layout at different inheritance levels

single inheritance

Interview summary: Goose factory Linux background development interview written examination C + + knowledge points reference notes
Interview summary: Goose factory Linux background development interview written examination C + + knowledge points reference notes

multiple inheritance

Interview summary: Goose factory Linux background development interview written examination C + + knowledge points reference notes
Interview summary: Goose factory Linux background development interview written examination C + + knowledge points reference notes
Interview summary: Goose factory Linux background development interview written examination C + + knowledge points reference notes


Finally, I finished writing a long article. On the one hand, I hope to give some references to students who want to come to goose factory or prepare to interview any company for C + + development. On the other hand, I review my knowledge. Buddy interested in programming and technology can pay attention to my official account.

I have sorted out the knowledge points of background development and learning mentioned in this paperE-books and learning materialsIn the official account.Back end technology school“Reply after paying attention”1024“You can get it for free. The materials and books are collected and sorted out during my study over the past few years and shared with you.

You can search the official account of WeChat for “back end technology school” to reply to “information”. The article is continuously updated every week. See you in the next issue!

Recommended Today

Implementation example of go operation etcd

etcdIt is an open-source, distributed key value pair data storage system, which provides shared configuration, service registration and discovery. This paper mainly introduces the installation and use of etcd. Etcdetcd introduction etcdIt is an open source and highly available distributed key value storage system developed with go language, which can be used to configure sharing […]