2024最新大厂C++面试真题合集,大厂面试百日冲刺 day2

腾讯wxg一面面经

虚函数、虚表、虚指针解释一下,分别在哪个时间段创建的。

虚函数:类中通过virtual关键字声明的函数,允许在派生类中被重写,实现多态。

虚表(虚函数表):一个存储类的虚函数地址的表,在编译时期创建,每个含有虚函数的类都有一个虚表。

虚指针(vptr):一个指针,指向对象的虚表,在对象实例化时(运行时)被创建,并初始化指向类的虚表。

select、poll、epoll的区别解释一下
  1. select: 它的文件描述符集合大小有限(通常受FD_SETSIZE宏限制),每次调用都需要复制整个文件描述符集,且在返回后需要遍历整个集合来找出活跃的文件描述符,这让它在处理大量文件描述符时效率较低。
  2. poll: 类似于select,但它不受文件描述符数量的限制,因为它使用动态数组(而不是固定大小的位数组)。同样,在每次调用时需要复制整个数组,并在返回后遍历数组以找出活跃的文件描述符。
  3. epoll: 仅在Linux系统上可用,它使用了一个事件列表,所以不需要像select或poll那样复制和遍历整个文件描述符集。epoll在首次监视某个文件描述符时向内核注册文件描述符,之后不需要再次注册,且当文件描述符就绪时,它只返回那些状态发生变化的文件描述符,这大大提高了效率,尤其适合处理大量文件描述符的场景。
内存池的基本原理解释一下。

内存池的基本原理是预先在内存中分配一大块连续的空间,并将这块空间划分为大小相等或不等的小块,用于满足程序运行时的内存分配请求。当程序请求分配内存时,内存池会从这些预分配的小块中找到一个合适的块返回,而不是直接向操作系统请求。同样,当内存被释放时,它会返回到内存池中,而不是归还给操作系统。这种方式可以减少频繁向操作系统申请和释放内存所造成的开销和碎片化问题,从而提高内存分配和回收的效率。

左值引用和右值引用的区别解释一下,为什么需要右值?

左值引用:
是对可寻址(即可以取地址)且非临时的对象的引用,例如变量。左值引用用&表示。

右值引用:
是对临时对象(即将被销毁、不能取地址的对象)或可移动对象的引用,它扩展了对象的生命周期。右值引用用&&表示。

为什么需要右值:
右值引用主要用于实现移动语义和完美转发。

  • 移动语义允许资源(如动态内存)从一个对象转移到另一个对象,减少不必要的临时对象复制,优化性能。
  • 完美转发允许模板函数将其接收到的参数以原来的值类别(左值或右值)转发到其他函数,这在模板编程和函数重载解析中很有用。
智能指针的基本原理,引用计数是线程安全的吗?智能指针是线程安全的吗?

智能指针的基本原理是通过封装一个原始指针,在对象的生命周期管理上提供自动化处理

引用计数在std::shared_ptr中默认是线程安全的,即多个线程同时创建或销毁同一shared_ptr实例是安全的,因为修改引用计数的操作是原子的。

智能指针的线程安全性取决于其操作。对于智能指针本身的管理(如赋值和析构),std::shared_ptr是线程安全的。但是,多个线程访问智能指针管理的对象并不一定是线程安全的,需要额外的同步机制来保护被管理对象。

多线程访问单例,你要怎么办?

双重检查锁定模式(Double-Check Locking)。步骤如下:

  1. 在访问单例对象之前,首先检查对象是否已经被创建,以避免锁定开销。
  2. 若单例对象未被创建,则进入同步块。同步块内部再次检查对象是否已创建,以防止多个线程同时通过第一次检查。
  3. 如果确认单例对象未被创建,此时创建单例实例。
stl::vector数据存在哪里?为什么不能在栈上?

std::vector的数据实际存储在堆(Heap)上。这是因为std::vector需要能够动态地增长或缩小其大小,而堆内存提供了动态内存分配的能力。栈(Stack)上的空间是有限且固定大小的,适合存储大小在编译时期就已确定的局部变量,不适合存储大小可变的std::vector

为什么栈比堆快?

栈比堆更快主要是因为其内存分配方式和访问速度。栈内存由操作系统自动管理,分配和释放速度非常快,因为它使用连续的内存块,并以后进先出的顺序进行访问。相反,堆内存分配更为灵活但也更复杂,需要程序员手动分配和释放,且可能产生内存碎片,这会影响访问速度。此外,栈内存访问通常涉及更少的指令和间接性。

unordered_map底层是什么?

unordered_map底层实现是一个哈希表。它通过使用哈希函数来把键转换为哈希值,然后根据这个哈希值把元素存储在相应的桶中。在碰到哈希冲突时,会通过链接法解决,即在同一桶中用链表链接存储所有哈希值相同的元素。

C++入口函数是什么?main函数之前执行的是什么函数?

C++的入口函数是main函数。在main函数执行之前,C++运行时会执行一些环境准备的工作,包括初始化静态存储持续期内的对象、执行非局部对象的构造函数等。这些通常涉及到全局对象的构建、静态对象的初始化,以及C++标准库和运行时库的初始化。不同的编译器和平台可能会有不同的启动例程,比如GCC的_start函数,在调用main函数之前设置程序运行的环境。

LeetCode 907

给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。

由于答案可能很大,因此 返回答案模 10^9 + 7

示例 1:

输入:arr = [3,1,2,4]
输出:17
解释:
子数组为 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。 
最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。

示例 2:

输入:arr = [11,81,94,43,3]
输出:444

提示:

  • 1 <= arr.length <= 3 * 104
  • 1 <= arr[i] <= 3 * 104

解题步骤如下:

  1. 单调栈:使用单调递增栈存储数组元素的索引,帮助快速找到每个元素左右两边第一个比它小的元素位置。
  2. 遍历数组:对数组每个元素进行遍历,对于每个遍历到的元素,进行以下操作:
    • 当栈不为空且当前元素小于栈顶元素对应的数组值时,弹出栈顶元素,并计算以该栈顶元素对应的值为最小值的子数组对总和的贡献。
    • 将当前元素的索引入栈。
  3. 处理栈中剩余元素:遍历结束后,栈中可能还有元素。这些元素对应的值是它们右侧所有子数组的最小值。类似地,计算它们对总和的贡献。
  4. 计算结果:遍历过程中累加每次计算的子数组最小值的总和。
  5. 返回结果:因为结果可能非常大,根据题目要求,返回总和对 10^9 + 7 取模的结果。

腾讯一面

windows和linux如何创建线程

在Windows和Linux上创建线程的方法如下:

Windows:
使用CreateThread函数创建线程。

#include <windows.h>

DWORD WINAPI ThreadFunc(LPVOID param) {
    // 线程函数
    return 0;
}

int main() {
    HANDLE thread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
    // 等待线程结束
    WaitForSingleObject(thread, INFINITE);
    CloseHandle(thread);
}

Linux:
使用pthread_create函数创建线程。

#include <pthread.h>

void* ThreadFunc(void* arg) {
    // 线程函数
    return NULL;
}

int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, ThreadFunc, NULL);
    // 等待线程结束
    pthread_join(thread, NULL);
}

在Windows中,使用Windows API(如CreateThread)创建线程;在Linux中,通常使用POSIX线程库(pthread)来创建线程。

线程和进程的区别,线程占用空间吗

线程和进程的主要区别在于资源管理和执行环境:

  1. 进程:是操作系统进行资源分配和调度的一个独立单位,拥有独立的地址空间和系统资源(如文件句柄和设备)。
  2. 线程:是进程内的执行流,是CPU调度和分派的基本单位,线程共享其所属进程的地址空间和资源,但拥有自己的执行堆栈、程序计数器和一系列寄存器。

线程占用空间:线程确实占用空间,主要包括线程栈(用于存储局部变量和调用历史)、线程本地存储区域和一些必要的管理信息,但相比进程,线程所需的资源和空间通常较少。

线程栈实现原理,线程栈是怎么存储数据的

线程栈的实现原理基于以下机制:

  1. 栈的分配:操作系统为每个线程分配一块连续的内存区域作为栈,用于存储执行流程中的数据。这块内存的大小通常是预设的,可以通过系统设置或程序指定调整。
  2. 数据存储:线程栈按照后进先出(LIFO)的原则存储数据。每当函数被调用时,函数的局部变量、函数参数和返回地址被推入栈顶;当函数返回时,这些信息被从栈中弹出,回到调用者环境。
  3. 栈帧(Stack Frame):每个函数调用在栈中占据一个栈帧。栈帧包含函数的局部变量、函数参数、返回地址和某些书keeping信息,如基指针(EBP)等。
  4. 指针管理:栈指针(SP)用于追踪栈顶的位置,确保数据正确地入栈和出栈。在函数调用过程中,基指针(BP)用于稳定地指向当前栈帧的开始,便于访问函数参数和局部变量。
malloc分配内存是在栈还是在堆

malloc分配的内存位于堆上。

进程结束不释放堆会产生泄露?

是的,如果进程结束时没有释放分配在堆上的内存,这些内存不会自动回收,从而会产生内存泄露。然而,在现代操作系统中,进程结束后,操作系统会回收该进程所使用的所有资源,包括堆内存。

new和malloc区别

newmalloc 的区别主要在于:

  1. 用途new是C++中用于分配内存的运算符,同时调用构造函数初始化对象;malloc是C中的库函数,仅分配内存。
  2. 返回类型new返回具体类型的指针,无需类型转换;malloc返回void*类型,需要显式转换为目标类型的指针。
  3. 内存初始化new分配内存后会自动调用构造函数初始化对象;malloc仅分配内存,不进行初始化。
  4. 配对操作newdelete配对使用,mallocfree配对使用。
  5. 错误处理new在无法分配内存时会抛出异常,而malloc则返回NULL
  6. 重载newdelete可以被重载;mallocfree不能被重载。
C++int占几个字节,指针呢

在C++中,int的大小通常是4个字节。指针的大小通常是4个字节(32位架构)或8个字节(64位架构)。

一般vs程序崩溃是什么原因造成的

Visual Studio程序崩溃通常由以下原因造成:

  1. 内存访问违规:试图访问无效内存地址。
  2. 资源泄露:大量消耗系统资源而未释放。
  3. 指针误用:空指针解引用或野指针操作。
  4. 异常未捕获:抛出异常且未被捕获处理。
  5. 堆栈溢出:无限递归或大量局部变量占用。
  6. 并发错误:多线程访问共享资源未同步。
  7. 第三方库错误:依赖库中的错误或不兼容。
  8. 硬件故障:如内存损坏等硬件问题。
  9. 调试器问题:VS本身的bug或插件造成的问题。
c++生成子类需要虚析构吗

是的,如果你的C++类设计为基类,并且你打算通过基类指针来删除派生类的对象,那么你应该为基类提供一个虚析构函数。这样做可以确保在删除基类指针时,派生类的析构函数会被正确调用,从而避免资源泄露或其他析构相关的问题。

C++虚函数底层是如何实现的

C++中虚函数的底层实现通常是通过虚函数表(虚表,vtable)来实现的。每个包含虚函数的类都有一个虚表,此表是一个包含指向类的虚函数的函数指针的数组。每个对象都包含一个指针(虚指针,vptr),指向其类的虚表。当调用虚函数时,实际上是通过对象的虚指针查找虚表,然后通过虚表调用对应的函数实现的,这允许在运行时进行多态行为。

虚表是存放在哪里的

虚表(vtable)通常存放在程序的只读数据段(.rodata section)中,这是因为虚表包含的函数地址不会在运行时改变。每个对象的虚指针(vptr)指向其类的虚表,确保正确调用对应类的虚函数。

什么是结构体对齐,结构体对齐规则,怎么判断结构体大小

结构体对齐是指在结构体中,每个成员的起始地址相对于结构体起始地址的偏移量是该成员大小的整数倍,这样做是为了满足某些硬件平台对数据存取对齐的要求,提高内存访问效率。

结构体对齐规则通常遵循以下原则:

  1. 结构体的起始地址能够被其最宽基本类型成员的大小所整除。
  2. 结构体每个成员相对于结构体起始地址的偏移量应是该成员大小的整数倍,不是的话会进行填充(padding)。
  3. 结构体的总大小为其最宽基本类型成员大小的整数倍。

判断结构体大小的方法是:

  1. 确定每个成员的大小和对齐要求。
  2. 根据成员声明顺序,为每个成员分配地址空间,必要时进行填充。
  3. 按最大成员对齐要求在结构体末尾可能添加填充。
  4. 结构体总大小就是最后一个成员末尾地址加上末尾填充(如果有的话)。

使用sizeof(结构体类型名)表达式可以直接得到结构体的大小。

C++里面左值引用和右值引用有什么区别

在C++中,左值和右值是取决于它们可以出现在赋值表达式的哪一边。左值通常出现在赋值表达式的左边,它是一个持久的对象,而右值通常出现在赋值表达式的右边,他们是临时的。

为什么提出右值引用,是为了解决什么

解决两个问题:

  1. 实现移动语义(Move Semantics):在C++11之前,对象间的操作主要是拷贝,这会引发额外的性能开销。有了右值引用,可以直接转移资源,而不仅仅是复制,这显著提高了性能。
  2. 支持完美转发(Perfect Forwarding):使用模板和右值引用,函数可以将其参数完美地转发给其他函数,保持原始参数的所有属性(如是左值还是右值,CV限定符等)。这在编写泛型代码(如STL容器)时十分有用,因为它减少了冗余和提高了性能。
线程间怎么同步,同步是解决什么问题

主要的目的是为了防止多个线程同时操作同一片内存空间,导致数据的不一致。

线程间的同步可以通过多种机制实现,包括但不限于以下几种:

  1. 互斥锁(Mutex):当一个线程使用互斥锁保护的资源时,其他需要这些资源的线程将被阻塞,直到该线程释放资源。
  2. 信号量(Semaphore):它是一个计数器,用来保护一个或者多个相同的资源。当没有可用资源时,需要这些资源的线程将被阻塞。
  3. 条件变量(Condition Variables):它可以用来让一个线程等待某个条件成立,而不是忙等。
  4. Event/Message Queue:线程通过发送和接收事件或消息进行通信。接收线程将阻塞,直到有事件或消息可接收。
如何避免死锁,死锁的条件是什么

避免死锁的一些常见策略包括:

  1. 破坏互斥条件:尽可能地减少对资源的互斥访问。
  2. 破坏持有和等待条件:一次性申请所有资源,而不是分步申请。
  3. 破坏不可抢占条件:使资源可以被抢占,当某个线程需要资源时,已经分配的资源可以被回收。
  4. 破坏循环等待条件:对资源请求进行排序,按照一定顺序获取资源。

死锁发生的条件有四个,通常被称为死锁的必要条件:

  1. 互斥:资源不能被共享,只能由一个线程同时使用。
  2. 持有和等待:线程已经持有至少一个资源,但又提出了新的资源请求,而该资源被其他线程持有。
  3. 不可抢占:线程持有的资源在未完成其任务前,不能被其他线程抢占。
  4. 循环等待:存在一种线程资源的循环等待关系。
vector底层是什么数据结构

vector底层是使用连续内存空间来实现的动态数组。

vector空间不够了底层会怎么做

vector空间不够时,它的底层实现会分配一个更大的连续内存块,将现有元素复制到新的内存块中,然后释放原来的内存块,并更新内部状态以反映新的容量。

vector resize是怎么做的

vectorresize操作主要完成以下步骤:

  1. 判断新的大小是否大于当前的容量,如果是,则需要额外分配内存空间。
  2. 如果新的大小比当前元素数量少,将会销毁多余的元素。
  3. 如果新的大小比当前元素数量多,将会在容器尾部创建新的元素。
  4. 更新内部的元素数量为新的大小。
C++里面的成员函数和普通函数有什么区别

在C++中,成员函数和普通函数的主要区别如下:

  1. 成员函数是类的组成部分,它们可以访问类的私有、保护和公共成员。而普通函数不是类的一部分,不可以直接访问类的私有和保护成员。
  2. 成员函数在调用时需要使用对象或者指向对象的指针或引用来调用,而普通函数则不需要。
  3. 成员函数可以被声明为虚函数,形成多态性。而普通函数不能。
  4. 成员函数可以被重载,但是不能被重定义。普通函数可以被重载,不能被重定义。
C++成员函数是怎么访问到成员变量的

C++中,成员函数可以直接访问属于相同类的成员变量,因为它们在调用时隐含地接收一个指向调用对象的指针(通常命名为this)。this指针提供了对调用对象成员变量的直接访问方式。

unity脚本如何与引擎绑定的

在Unity中,脚本与具体的游戏对象(引擎实体)绑定的方式一般如下:

  1. 首先,创建一个脚本。这可以通过Unity编辑器的"Assets"菜单,选择"Create" -> “C# Script”。
  2. 接着,将这个脚本拖放到游戏对象上,或者在游戏对象被选中的情况下,直接在检查器窗口点击"Add Component",然后选择你的脚本。

这样,你的脚本就与指定的游戏对象绑定了。然后脚本内的函数就可以通过this.gameObject来访问和控制绑定的游戏对象。

momenta 系统研发C++实习生一面二面

讲一下no except如果出现了异常会怎么办?

如果在声明为noexcept的函数中出现了异常,程序会调用std::terminate()来立即终止程序执行。

emplace back,vector里面emplace back是什么

emplace_back 是一种方法,用于在向量尾部直接构造和添加一个新的元素,而无需额外的复制或移动操作。它接受的参数是将要添加的元素的构造函数参数,而不是已构造的元素本身。这个方法可以提高代码效率,因为省去了不必要的构造和析构过程。

右值引用是怎么样的,如果没写右值引用的函数呢?

右值引用是C++11引入的一种引用类型,用于绑定到临时对象(右值)。使用右值引用可以避免不必要的对象拷贝,从而提高程序效率。如果某个函数未提供右值引用版本,当需要传递临时对象作为参数时,会按照传统的拷贝或移动的方式处理,这可能会导致额外的拷贝开销。右值引用通过允许直接修改临时对象(通过移动语义),减少了这种不必要的拷贝,优化了性能。

在写webserver的时候,socket编程是阻塞还是非阻塞的,边缘触发和水平触发的区别是什么

在编写 webserver 的时候,socket 编程可以是阻塞的,也可以是非阻塞的,具体取决于你的需求和设计。阻塞socket会在没有数据可读或者无法立即写入数据时使调用的线程阻塞,而非阻塞socket则不会。

边缘触发和水平触发是IO多路复用中的概念。水平触发(LT)模式下,只要socket处于可读或可写状态,无论是否有新的IO事件,都会触发通知。而边缘触发(ET)模式下,只有在状态发生改变时才会触发通知,比如从不可读写变为可读写时。

C++的多态是怎么做到的—模板编程和虚函数

C++的多态主要通过虚函数来实现。在基类中定义虚函数,在派生类中重写该函数,通过基类的指针或引用来调用虚函数时,会根据对象的实际类型动态绑定到适当的函数,这样就实现了运行时多态。C++的函数重载和模板也可以实现编译时的多态。

虚函数和虚函数表

虚函数允许派生类重写基类中的函数行为。如果一个类的函数被声明为虚函数,那么在此类的对象中将会有一个虚函数表(Virtual Table,通常称为v-table),它存储了虚函数地址的指针。对象使用这个表来解析函数调用的具体实现,这样可以在运行时根据对象的实际类型调用正确的函数,实现动态绑定。

队列之间是怎么同步消息,mmap解释一下怎么通信的?

队列之间通常通过锁(如互斥锁)和条件变量来同步消息,确保在写入和读取数据时能够正确地协调不同线程或进程间的行为,防止数据竞争和不一致状态。

mmap是一种内存映射文件的技术,它可以将文件或设备的内容映射到进程的地址空间。通过mmap创建的内存区域可以被多个进程共享,从而实现进程间通信(IPC)。当一个进程修改了内存映射区域的内容,这些修改将会反映到磁盘文件上,其他共享同一个映射的进程也能看到这些变更,实现了进程间的数据同步。

extern有什么用,为什么要这样做呢,不这样做为什么报错

extern 关键字在C++中用于声明一个全局变量或函数的存在,但不定义它。当你在多个文件中共享同一变量或函数时,extern 告诉编译器这个标识符是在其他地方定义的,可以在不同的编译单元中使用它。

这样做的原因是,C++对于任何给定的变量或函数,只允许在一个地方进行定义(也就是分配存储空间),但它可以在其他多个地方声明。如果没有使用extern,并且在多个文件中定义相同的变量或函数,链接器将会报错,因为它找到多个相同名称的符号定义,这违反了One Definition Rule(ODR)。

如果不使用extern而直接在多个文件中定义相同的全局变量,则每个定义都会在各自文件的翻译单元中分配内存,导致多份副本存在。这会在链接时导致重复定义的错误。使用extern可以避免这个问题,确保只有一份变量的定义和分配存储空间,而其他文件中则通过extern声明来引用这个全局变量。

四个cast讲一下,dynamic_cast和static_cast是在什么时候转换的?

在C++编程中,有四种类型的类型转换操作,分别是static_castdynamic_castconst_cast以及reinterpret_cast

  • static_cast是用于在已知的相关类型之间进行转换,比如整型和浮点型、指向基类的指针与指向派生类的指针之间的转换。它在编译时进行类型检查。
  • dynamic_cast主要用于处理多态,即将基类指针或引用安全地转换为派生类的指针或引用,并在运行时检查类型的转换是否安全。这种转换只有在类型为多态类型时才能使用,也就是说,这个类型必须包含至少一个虚函数。如果转换不成功,对于指针类型会返回nullptr,对于引用类型会抛出std::bad_cast异常。
如果dynamic_cast是在运行时转换,原理是什么?

dynamic_cast在运行时进行类型转换的原理基于对象的运行时类型信息(RTTI)。当使用dynamic_cast进行向下转型时(即将基类指针或引用转换为派生类指针或引用),它会使用RTTI来检查对象的实际类型是否与目标类型兼容。如果转换合法,dynamic_cast会返回转换后的指针或引用;如果不合法,它会返回nullptr(对于指针类型)或抛出std::bad_cast异常(对于引用类型)。这个检查过程确保了类型转换的安全性,避免了无效的转换。

type-id是什么?RTTI了解过多少?

type_id是指typeid操作符,它是C++中运行时类型信息(RTTI)的一部分。typeid用于获取一个表达式的类型信息。它可以用来在运行时识别对象的确切类型,并提供std::type_info对象,该对象包含了类型的相关信息,例如类的名称。

RTTI是C++语言的一项特性,提供了在运行时确定对象类型的能力。RTTI主要包括两个部分:typeid操作符和dynamic_cast操作符。它们允许在对象的类层次结构中执行类型安全的转换,并在运行时检查对象类型。RTTI通常用于多态场合,当需要在运行时判断对象的实际类型时非常有用。然而,RTTI也有一定的性能开销,并不总是被开发者所启用。

设计模式了解多少?单例模式怎么实现的?magic static怎么保证线程安全

单例模式通常通过将构造函数设置为私有来限制对象的创建,并提供一个静态方法来获取类的唯一实例。使用magic static 可以保证线程安全。

magic static指的是C++11标准中引入的特性,即局部静态变量的初始化是线程安全的。这意味着如果多个线程同时首次访问getInstance()方法,编译器和运行时环境会保证仅有一个线程可以初始化instance,而其他线程将等待,直到初始化完成。这样就在不使用锁的情况下保证了线程安全。

解释一下static关键字的用法?static的初始化是在什么时候的?

static关键字在C++中有多种用法:

  1. 静态局部变量:在函数内部声明的static变量,其生命周期跨越整个程序运行期,但仅在该函数作用域内可见。它只被初始化一次,即在第一次进入函数时。
  2. 静态类成员:用static声明的类成员变量或函数属于整个类,而不是类的某个特定对象。静态成员函数只能访问静态成员变量或其他静态成员函数。
  3. 静态全局变量或函数:在文件的全局作用域中声明的static变量或函数限定了其链接范围,使它们仅在定义它们的文件内可见。

对于初始化时机:

  • 静态局部变量在程序的执行流首次通过该变量定义时进行初始化。
  • 静态全局变量和静态类成员变量在程序启动(进入main函数之前)时初始化。
  • 如果存在多个静态变量的初始化顺序依赖,那么在同一个编译单元(文件)内,它们按照定义的顺序进行初始化。跨编译单元的初始化顺序是未定义的,可能导致静态初始化顺序问题。
git rebase和merge的原理讲一下?

git merge: git merge 命令将两个分支的更改合并到一起。当你执行一个合并时,Git 会尝试自动融合不同分支的更改。如果两个分支在相同的文件行上有修改,那么可能会发生冲突,需要手动解决。合并完成后,会产生一个新的“合并提交”来表示这次合并。

git rebase: git rebase 命令的本质是将一系列提交从一个分支上取下来,然后再应用到另一个分支上。Rebase 重新写作了提交历史,它通过将提交一一复制到新的基底之上来实现。这个过程可以使历史更线性,但是会改变现有的提交历史。需要注意的是,对于已经公开的分支执行 rebase 操作可能会导致问题,因为它会改变提交历史。

如果我在某一个feature分支开发了2个月,这个时候要回去dev分支或者主分支,你应该用哪个命令?

在一个feature分支上开发了较长时间,且希望将这些更改合并回dev分支或主分支,可以使用git mergegit rebase命令。

  • 如果您希望在历史记录中保留feature分支的合并点,保证完整性和合并的上下文,您应该使用git merge
  • 如果您想要一个更干净、线性的历史记录,可以选择使用git rebase先重新定位您的feature分支上的更改(确保先与dev分支同步),然后再将其合并回dev分支或主分支。但请注意,如果feature分支的更改是公开的并被其他人所使用,使用git rebase可能导致协作上的问题。

收集整理了一份2024年最新C++开发学习资料,既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C++开发知识点,真正体系化!
包含大厂面经、学习笔记、实战项目、大纲路线、讲解视频 领取地址:
https://docs.qq.com/doc/DR2N4d25LRG1leU9Q
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值