对象初始化、销毁、拷贝与移动
开发者自定义类的构造函数和析构函数应尽可能轻量高效,因为它们可能在开发者未预料的情况下被调用。保持这些方法简单小巧还能让编译器进行内联优化,从而提升性能。同样的原则也适用于拷贝构造函数和移动构造函数——应尽量简化,并优先使用移动构造函数而非拷贝构造函数。在需要极致优化的场景下,开发者甚至可以删除默认构造函数和拷贝构造函数,以避免不必要的或意外的对象拷贝。
引用与指针的使用
C++ 的许多特性都围绕通过 this
指针隐式访问类成员构建,因此无论开发者是否显式操作,通过引用和指针访问对象的情况非常普遍。通过指针或引用访问对象的效率通常与直接访问相当,因为现代处理器对指针解引用有硬件优化支持。
主要缺点:
指针本身占用一个寄存器。
需要额外的解引用指令来访问目标变量。
指针算术的性能与整数运算相当,但计算两个指针之间的差值需要除以对象大小,可能较慢(若对象大小是 2 的幂次方则无此问题,这在基本类型和优化结构中很常见)。
智能指针
智能指针(如 std::unique_ptr
、std::shared_ptr
、std::weak_ptr
)是现代 C++ 的核心特性,提供动态内存的安全管理(RAII 模式)。
• std::shared_ptr
因引用计数会有额外开销,但通常整体影响较小。
• 若智能指针数量过多,则可能累积显著开销。
指针别名问题与编译器优化
指针可能导致 指针别名(Pointer Aliasing) 问题,即编译器无法确定两个指针是否指向同一内存地址,从而禁用某些优化。例如:
void func(int* a, int* b, int n) { for (int i = 0; i < n; ++i) { a[i] = *b; // 编译器无法确认 *b 是否在循环中变化 } }
上述代码中,即使 *b
实际是常量,编译器仍可能无法优化循环(如将 *b
提取到循环外)。
解决方案
使用
__restrict
关键字(编译器提示无别名):void func(int *__restrict a, int *__restrict b, int n) { for (int i = 0; i < n; ++i) { a[i] = *b; // 编译器可安全优化 } }
注意:这是提示而非强制,效果取决于编译器。
全局启用
-fstrict-aliasing
编译选项(假设无指针别名)。
关键点总结
• 构造/析构函数:保持轻量,优先移动语义。
• 引用/指针:高效但占用寄存器,注意解引用开销。
• 智能指针:安全但需权衡开销。
• 指针别名:可能阻碍优化,可通过 restrict
或编译选项解决。
系统当前共有 426 篇文章