96SEO 2026-02-20 08:33 0
虚函数表:存在于类中,不同的对象共享一张虚函数表。

虚函数表包含类的虚函数的地址,虚函数表指针位于对象内存头部,指向虚函数表。
虚函数:查找虚函数表中的指针访问派生类中的函数。
fun()=0,含有纯虚函数的类为抽象类,不能实例化,纯虚函数必须在子类实现
j不能改变常指针指向的内存地址,int
修饰类的成员函数,表示该函数不会修改类中的数据成员,不会调用其他非const的成员函数
修饰的函数,只能调用const函数,非const函数可以调用const函数
new/delete会调用构造/析构,无需指定内存大小,malloc返回void*,再强制转换成所需要的类型
修饰的局部变量作用范围为该函数体,不同于auto变量,其内存只被分配一次,因此其值在下次调用的时候维持了上次的值
模块内:static修饰全局变量或全局函数,可以被模块内的所有函数访问,但是不能被模块外的其他函数访问,使用范围限制在声明它的模块内
类中成员变量:表示该变量属于整个类所有,对类的所有对象只有一份拷贝
类中成员函数:表示该函数属于整个类所有,不接受this指针,只能访问类中的static成员变量
注意和const的区别!
!
!
const强调值不能被修改,而static强调唯一的拷贝,对所有类的对象
vector:底层是数组。
空间不足时,分配目前空间的两倍,然后将元素移动到新容器。
deque:双向队列。
可以在前端或后端进行扩容。
priority_queue:底层是vector,heap(堆)作为处理规则,heap本质是一棵完全二叉树
set和map:底层是红黑树,红黑树又是基于链表实现,因此占用内存较小
unordered_set和unordered_map:底层是基于哈希表实现的
红黑树是一种二叉搜索树,但是它多了一个颜色的属性。
红黑树的性质如下:1)每个结点非红即黑;2)根节点是黑的;3)如果一个结点是红色的,那么它的子节点就是黑色的;4)任一结点到树尾端(NULL)的路径上含有的黑色结点个数必须相同。
通过以上定义的限制,红黑树确保没有一条路径会比其他路径多出两倍以上;因此,红黑树是一种弱平衡二叉树,相对于严格要求平衡的平衡二叉树来说,它的旋转次数少,所以对于插入、删除操作较多的情况下,通常使用红黑树。
保证同一时间段内只有一个智能指针能指向该对象(就像rust的所有权)
多个共享指针可以指向相同的对象,采用了引用计数的机制,当最后一个引用销毁时,释放内存空间。
https://blog.csdn.net/mick_hu/article/details/100931034
id="一内存管理与资源生命周期-memory--raii">一、内存管理与资源生命周期
互相持有导致内存泄漏(解法:std::weak_ptr)。
shared_from_thisstd::terminate(程序直接挂掉,严禁在析构中抛异常)。
Fragmentation),在图形学中常见于粒子系统(解法:Pool
id="1-shared_ptr-的循环引用与内存泄漏">1.
Graph)或双向链表中,父节点持有子节点,子节点又反向持有父节点。
互相指,引用计数永远不为0std::shared_ptr<Node>
std::make_shared<Node>();auto
std::make_shared<Node>();a->neighbor
id="2-enable_shared_from_this-的崩溃陷阱">2.
enable_shared_from_this
shared_from_this()
std::enable_shared_from_this<Widget>
shared_ptrstd::shared_ptr<Widget>
std::make_shared<Widget>();
id="3-make_shared-的内存滞留问题-the-weak-ptr-bloat">3.
Block)分配在同一块连续内存中。
只要还有一个
活着,整个控制块就不能释放。
因为控制块和对象是一体的,这导致对象占用的内存也无法归还给
std::shared_ptr<BigObject>
id="4-自定义-deleter-导致的-abi-兼容性灾难">4.
std::unique_ptr<T,是类型的一部分。
unique_ptr<File,
CloseFile>
是不同类型,无法互转,且导致模板膨胀。
std::shared_ptr<T>:Deleter如果修改了删除器逻辑,函数签名可能都要变,这在库设计中是致命的。
id="5-析构函数抛出异常-destructor-throwing-exception">5.
flush(),结果失败了,你顺手抛了个异常。
Unwinding,即因为一个异常正在处理而销毁局部变量)的过程中,析构函数又抛出了第二个异常,程序会直接调用
id="6-裸指针与智能指针混用的-double-free">6.
独立接管同一个裸指针。
它们互不知道对方存在,都会尝试析构该对象。
int(10);std::shared_ptr<int>
raw_ptrstd::shared_ptr<int>
id="7-vectorbool-的代理陷阱">7.
vector<bool>
vector<bool>
bool&,而是一个临时代理对象(Proxy
autoclass="language-cpp">std::vector<bool>
std::vector<bool>::reference
static_cast<bool>(features[0]);
id="二对象模型与面向对象-object-model--oop">二、对象模型与面向对象
static_cast
将派生类对象赋值给基类对象(非指针/引用),导致派生类特有的部分被“切掉”,多态失效。
通过基类指针删除派生类对象,若基类析构非虚,导致派生类析构函数不执行(内存泄漏)。
id="1-多重继承下的指针漂移-the-pointer-adjustment-trap">1.
static_cast<PhysicsBody*>(e);
static_cast<PhysicsBody*>(user_data);
id="2-对象切片-object-slicing-与-stl-容器">2.
std::vector<Shape>
std::vector<Shape*>。
当你把一个
Circle特有的半径、虚函数表指针(vptr)全被“切”掉了。
std::vector<std::unique_ptr<Shape>>
id="3-构造析构函数中调用虚函数-virtual-call-in-ctordtor">3.
getLogName()。
id="4-非虚析构函数导致的内存泄漏-non-virtual-destructor">4.
~Base(),完全无视
Derivedid="5-dynamic_cast-的性能陷阱">5.
(dynamic_cast<Player*>(obj))。
Information),它需要遍历继承树进行字符串比较(或类似机制)。
在高频循环(如每帧的渲染循环)中使用它,是性能杀手。
dynamic_cast<Player*>(e))
dynamic_cast<Monster*>(e))
id="6-虚函数的默认参数-default-arguments-in-virtual-functions">6.
默认参数是静态绑定的,而函数调用是动态绑定的。
这意味着:你可能调用了
Derivedid="三stl-与-容器陷阱-stl--containers">三、STL
考察对标准库实现原理的理解,尤其是性能敏感的场景。
noexcept,std::vector
Guarantee),会强制退化为拷贝(Copy),导致严重的性能下降。
std::mapstd::unordered_map:
O(1),但在扩容(Rehash)或哈希冲突严重时性能极不稳定,且内存占用更高。
图形学中高性能场景常慎用
unordered_map。
operator==,且必须满足严格弱序(Strict
id="1-迭代器失效与悬垂引用-iterator-invalidation--dangling-refs">1.
enemies.push_back(new_enemy)。
vector不够,它会申请一块新的、更大的内存,把旧数据搬迁过去,然后释放旧内存。
指针指向的是已经被释放的旧内存(Use-After-Free)。
id="2-vector-扩容时的性能杀手未标记-noexcept-的移动构造">2.
vectorTexture,包含大块内存),并为其写了移动构造函数
std::vector<Texture>。
vector为了保证“强异常安全保证”(如果不成功,原来的数据不能坏),它不敢调用你的移动构造函数(因为万一移动到一半抛异常,旧数据已经被破坏了,无法回滚)。
noexceptBigObj(BigObj&&
正确写法:显式告诉编译器这个函数绝不抛异常BigObj(BigObj&&
id="3-在循环中错误地删除元素-erase-in-loop">3.
遍历一个列表,删除满足条件的元素(比如删除所有死亡的怪物)。
iter会使当前迭代器失效,但返回下一个有效的迭代器。
很多初学者会忘记接住返回值,或者在
eraseid="4-stdmap-vs-stdunordered_map-的陷阱">4.
std::unordered_map
unordered_map。
Hash。
这在实时渲染中会导致明显的帧生成时间突刺(Spike)。
id="5-stdstring_view-的生命周期陷阱-c17">5.
class="language-cpp">std::string_view
id="6-mapoperator-的副作用">6.
不存在,operator[]
莫名其妙变大,还可能导致逻辑错误(本意是“只读”,结果变成了“写入”)。
id="7-reserve-vs-resize-的混淆">7.
reservecapacity),不创建对象(size
class="language-cpp">std::vector<int>
v.push_back(1);std::vector<int>
id="四性能优化与底层细节-performance--low-level">四、性能优化与底层细节
虚函数调用需要查表,破坏指令流水线(Pipeline)且不利于内联(Inline)。
Line,导致核心间频繁同步缓存,性能断崖式下跌(解法:alignas
id="1-虚函数的真实开销-the-cost-of-virtual-functions">1.
编译器不知道运行时会调用哪个函数,因此无法将函数体展开。
对于简短的函数(如
dotproduct),函数调用的入栈出栈开销比计算本身还大。
id="2-内存对齐与-padding-structure-padding--alignment">2.
你设计了一个粒子结构体,想要尽可能节省显存/内存带宽。
访问速度,会对结构体成员进行对齐。
如果不注意顺序,会产生大量的“填充字节”
id="3-simd-崩溃陷阱-the-alignment-crash">3.
Eigen::Vector4f,默认的
newid="4-伪共享-false-sharing">4.
你写了一个多线程物理求解器,每个线程负责更新数组中的一个计数器。
data[0]data[1],但这两个变量可能位于同一个
id="5-分支预测失败-branch-prediction-failure">5.
会“猜”走哪条路并预先执行。
如果猜错了(Misprediction),需要清空流水线重来,代价昂贵(约10-20个周期)。
“为什么处理排序后的数组比处理乱序数组快很多?
”(即使是同样的循环逻辑)。
id="6-矩阵遍历的-cache-friendly-问题">6.
img[x][y],每次访问都跳跃一行内存,导致几乎每次读取都是
id="7-rvonrvo-返回值优化">7.
move,编译器也会直接在调用者的栈帧上构造对象,实现“零拷贝”。
class="language-cpp">std::vector<int>
id="五并发与多线程-concurrency">五、并发与多线程
现代图形引擎都是多线程的,这是必考题。
不保证原子性也不保证线程同步,只防止编译器优化,面试中千万别说用
多个互斥锁获取顺序不一致导致死锁(解法:std::lock
std::scoped_lock)。
id="1-数据竞争-data-race-与-volatile-的致命误区">1.
并不是一条指令,它分为“读-改-写”三步。
如果没有同步机制,两个线程可能读到同一个旧值,导致计数丢失。
只防止编译器优化(比如把变量缓存到寄存器),它不提供原子性,也不提供内存屏障(Memory
{std::lock_guard<std::mutex>
id="2-死锁-deadlock-与锁顺序">2.
能够保证以某种全局一致的顺序上锁,或者原子地上锁std::scoped_lock
id="3-条件变量的虚假唤醒-spurious-wakeup">3.
可能会在没有任何人通知的情况下醒来(这是操作系统调度层面的副作用)。
class="language-cpp">std::queue<int>
{std::unique_lock<std::mutex>
id="4-线程生命周期与悬垂引用-dangling-reference-in-threads">4.
你在函数里启动了一个线程,为了方便,你捕获了局部变量的引用。
主线程函数执行完毕,局部变量被销毁(栈解退)。
子线程此时才开始运行,访问了已经销毁的变量。
id="5-stdasync-的同步阻塞陷阱">5.
对象,在其析构函数中会阻塞等待任务完成。
如果你不保存返回值,这行代码实际上变成了同步调用。
std::this_thread::sleep_for(std::chrono::seconds(1));
1秒std::async(std::launch::async,
析构,阻塞!
std::async(std::launch::async,
阻塞!
std::async(std::launch::async,
id="6-单例模式的双重检查锁-double-checked-locking">6.
id="7-原子操作不仅仅是-int-atomic-structs">7.
intstd::atomic<T>
指令级原子(Lock-free)。
否则,编译器会自动在该原子变量里塞一把锁。
std::atomic<T>::is_lock_free()。
如果返回
mutexid="六编译与链接-compilation--linking">六、编译与链接
如果
id="1-静态初始化顺序灾难-static-initialization-order-fiasco">1.
标准不保证不同编译单元(.cpp文件)之间全局变量的初始化顺序。
id="2-odr-违规-one-definition-rule-violation">2.
global_config
global_config
出现多次,但必须完全一样。
如果因为宏定义
#ifdef内存布局不一样,链接器不会报错,但运行时会发生诡异的内存覆盖。
id="3-头文件循环依赖-circular-dependency">3.
Player(比如记录持有者)。
对方,预处理器陷入死循环,或者编译报错“类型未定义”。
#include,什么时候用前置声明
id="4-inline-函数的链接错误">4.
inlineinline,为了代码整洁,你把声明写在
.h,定义写在函数的设计初衷是直接嵌入调用处,编译器通常不会为它生成独立的函数体符号(Symbol)。
函数的定义必须在每个调用它的编译单元中可见(通常直接写在
.hid="5-name-mangling-与-extern-c">5.
Vector<int>,
Vector<float>,
Vector<double>
class="post-meta-container">
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback