Learning C++ (Day 2)

1. 智能指针 unique_ptr

std::unique_ptr<Shape> p = std::make_unique<Circle>(); 与Shape* p = new Circle(); 在底层调用多态函数时的行为完全一致,但在生命周期管理、异常安全、所有权表达及工程防错上有着本质区别。

std::unique_ptr vs 裸指针(多态场景对比)

维度 Shape* p = new Circle();(裸指针) std::unique_ptr<Shape> p = std::make_unique<Circle>();(智能指针)
生命周期 手动管理:必须显式编写 delete p;,极易遗忘导致泄漏 RAII 自动管理:离开所在作用域({})自动释放,零泄漏
异常安全 差:提前 return 或中途抛出异常,delete 被跳过即泄漏 强:栈展开(Stack Unwinding)保证必定触发析构与释放
所有权语义 模糊:无法表达是“拥有者(Owner)”还是“借用者(Borrower)” 清晰独占:明确表达独占该资源,禁止拷贝,仅支持所有权移动(Move-only)
防错能力 低:允许随意浅拷贝,极易造成悬垂指针(Dangling Pointer)与重复释放(Double-Free) 高:编译器直接拦截拷贝构造/赋值,从源头杜绝多次释放
性能/空间开销 64 位平台占 8 字节 零开销抽象:同样仅占 8 字节,无引用计数,内联后机器码与原生指针相同
基类虚析构 必须具备:缺失 virtual ~Base() 触发未定义行为(UB) 必须具备:默认删除器底层仍执行 delete,同样依赖基类虚析构

核心工程实践准则

  1. 拥有即管理:堆对象创建与所有权持有统一使用 std::make_unique<Derived>(),业务代码杜绝裸 new / delete。
  2. 借用不接管:仅需访问对象接口时,函数形参使用 const Base&(推荐)或 Base*(允许空值),不传递智能指针所有权。
  3. 致命共性约束:多态基类析构函数必须显式声明为虚析构(virtual ~Base() = default;),智能指针无法替你规避非虚析构的 UB。

2. 纯虚函数 && 抽象类

什么是纯虚函数?在声明虚函数时,在函数声明的末尾加上 = 0,它就成了纯虚函数。纯虚函数没有具体的实现代码(或者说不需要在基类中强制实现),它只定义了函数的名称、参数和返回值类型。
在 C++ 标准中,只要一个类拥有(声明或继承且未实现的)至少一个纯虚函数,它就必然是抽象类。

#include <iostream>

// 抽象类:含纯虚函数,不能实例化
class Animal {
public:
    virtual void speak() = 0; // 纯虚函数
    virtual ~Animal() = default;
};

// 派生类:必须实现 speak
class Dog : public Animal {
public:
    void speak() override {
        std::cout << "汪汪!\n";
    }
};

int main() {
    // Animal a;      // ❌ 编译报错:抽象类不能直接创建对象

    Dog dog;
    Animal* p = &dog; // ✅ 允许使用抽象类指针/引用
    p->speak();       // 运行时多态:输出 "汪汪!"
}
posted @ 2026-10-09 17:48  カガリ  阅读(9)  评论(0)    收藏  举报