C++ 八股文(高级 C++ 特性)

1. C++ 中的右值引用和移动语义是什么?

1. 右值引用概念: 使用&&声明的引用类型,可以绑定到临时对象(右值),左值是有名字的对象右值是临时对象,右值引用延长临时对象的生命周期,是实现移动语义的基础。

2. 移动语义: 转移资源所有权而不是拷贝,避免深拷贝提高性能,移动后的对象处于有效但未定义状态,通过移动构造函数和移动赋值运算符实现,时间复杂度从O(n)降到O(1)。

3. 值类别: 左值lvalue(有名字可取地址),纯右值prvalue(临时对象字面量),将亡值xvalue(std::move的结果),左值引用绑定左值右值引用绑定右值,const左值引用可以绑定右值。

4. 使用场景: 返回大对象避免拷贝,容器插入临时对象,unique_ptr转移所有权,完美转发保持值类别,swap操作使用移动提高效率。

class Buffer {
    char* data;
    size_t size;
public:
    // 移动构造
    Buffer(Buffer&& other) noexcept 
        : data(other.data), size(other.size) {
        other.data = nullptr;  // 转移所有权
    }
    
    // 移动赋值
    Buffer& operator=(Buffer&& other) noexcept {
        if(this != &other) {
            delete[] data;
            data = other.data;
            other.data = nullptr;
        }
        return *this;
    }
};

Buffer b1(1024);
Buffer b2 = std::move(b1);  // 移动,不拷贝

2. C++ 中的 std::move 和 std::forward 有什么区别?

1. std::move作用: 无条件将左值转换为右值引用,不移动任何东西只是类型转换,告诉编译器可以移动这个对象,实际移动由移动构造/赋值完成,使用后源对象不应再使用。

2. std::forward作用: 完美转发保持参数的值类别,左值转发为左值右值转发为右值,用于模板函数转发参数,避免不必要的拷贝,实现泛型代码的高效转发。

3. 使用场景: move用于明确表示转移所有权,forward用于模板函数的参数转发,move是无条件转换forward是有条件转换,move用于实现移动语义forward用于实现完美转发。

4. 实现原理: move等价于static_cast<T&&>,forward根据模板参数决定转换类型,都是编译期操作无运行时开销,正确使用可以显著提高性能。

// std::move:无条件转换为右值
std::string str = "hello";
std::string str2 = std::move(str);  // str被移动

// std::forward:完美转发
template<typename T>
void wrapper(T&& arg) {
    func(std::forward<T>(arg));  // 保持arg的值类别
}

wrapper(10);        // 右值,forward转发为右值
int x = 10;
wrapper(x);         // 左值,forward转发为左值

3. C++11 中的 Lambda 表达式是什么?

1. 基本语法:捕获列表 mutable noexcept -> 返回类型 { 函数体 },捕获列表指定外部变量的访问方式,参数列表和普通函数相同,返回类型可以省略由编译器推导。

2. 捕获方式: []不捕获,[=]按值捕获所有变量,[&]按引用捕获所有变量,[this]捕获this指针,[x, &y]混合捕获,[=, &x]默认按值x按引用,C++14支持初始化捕获。

3. 特性: mutable允许修改按值捕获的变量,noexcept声明不抛异常,泛型lambda使用auto参数(C++14),constexpr lambda编译期计算(C++17),模板lambda(C++20)。

4. 使用场景: STL算法的谓词函数,回调函数和事件处理,线程函数,延迟计算和惰性求值,替代函数对象简化代码。

// 基本用法
auto add = [](int a, int b) { return a + b; };
int sum = add(3, 4);

// 捕获外部变量
int x = 10;
auto f1 = [x]() { return x * 2; };      // 按值捕获
auto f2 = [&x]() { x++; };              // 按引用捕获
auto f3 = [=, &x]() { return x + y; };  // 混合捕获

// 初始化捕获(C++14)
auto f4 = [ptr = std::make_unique<int>(42)]() { return *ptr; };

// 泛型lambda(C++14)
auto print = [](auto x) { std::cout << x; };

4. 如何使用 C++ 中的 constexpr 定义常量表达式?

1. 基本概念: constexpr声明的变量或函数可以在编译期求值,比const更强要求编译期可计算,constexpr变量必须用常量表达式初始化,constexpr函数可以在编译期或运行期执行。

2. constexpr函数: 函数体必须是单一return语句(C++11)或满足一定限制(C++14放宽),参数和返回值必须是字面类型,可以递归调用,用常量参数调用时编译期求值。

3. constexpr类: 构造函数可以是constexpr,成员函数可以是constexpr,C++14支持constexpr成员变量修改,可以创建编译期对象,用于模板元编程和编译期计算。

4. 使用场景: 数组大小和模板参数,编译期计算避免运行时开销,类型萃取和元编程,constexpr if实现编译期分支(C++17),性能优化和代码生成。

// constexpr变量
constexpr int size = 100;
int arr[size];  // 编译期常量

// constexpr函数
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n-1);
}
constexpr int val = factorial(5);  // 编译期计算

// constexpr类
class Point {
    int x, y;
public:
    constexpr Point(int x_, int y_) : x(x_), y(y_) {}
    constexpr int getX() const { return x; }
};
constexpr Point p(3, 4);
constexpr int x = p.getX();  // 编译期求值

// constexpr if(C++17)
template<typename T>
auto getValue(T t) {
    if constexpr (std::is_pointer_v<T>)
        return *t;
    else
        return t;
}

5. C++ 中如何实现自定义的内存管理器?

1. 基本方法: 重载operator new和operator delete全局或类级别,实现allocate和deallocate函数,使用内存池预分配内存,实现STL兼容的allocator接口。

2. 内存池实现: 预分配大块内存减少系统调用,维护空闲链表快速分配,固定大小块或多级大小,使用位图或链表管理空闲块,注意线程安全和内存对齐。

3. STL allocator: 实现allocate、deallocate、construct、destroy,定义value_type等类型别名,支持rebind转换为其他类型的allocator,C++17简化了allocator接口。

4. 使用场景: 频繁分配释放小对象,减少内存碎片,实时系统避免不确定延迟,嵌入式系统精确控制内存,性能敏感的应用优化分配速度。

// 简单内存池
class MemoryPool {
    union Block { Block* next; char data[32]; };
    Block* freeList = nullptr;
    
public:
    void* allocate() {
        if(!freeList) expandPool();
        Block* block = freeList;
        freeList = freeList->next;
        return block;
    }
    
    void deallocate(void* ptr) {
        Block* block = static_cast<Block*>(ptr);
        block->next = freeList;
        freeList = block;
    }
};

// STL allocator
template<typename T>
class PoolAllocator {
public:
    using value_type = T;
    
    T* allocate(size_t n) {
        return static_cast<T*>(pool.allocate());
    }
    
    void deallocate(T* p, size_t n) {
        pool.deallocate(p);
    }
};

std::vector<int, PoolAllocator<int>> vec;

6. C++ 中的模板元编程(Template Metaprogramming)是什么?

1. 基本概念: 使用模板在编译期进行计算和代码生成,模板实例化时执行计算,结果是编译期常量或类型,图灵完备可以实现任意计算,性能优于运行期计算但编译时间长。

2. 实现技术: 模板递归实现循环,模板特化实现条件分支,类型作为值传递,constexpr函数简化元编程(C++11),变参模板处理任意数量参数(C++11)。

3. 应用场景: 编译期计算常量(阶乘、斐波那契),类型萃取和类型操作,表达式模板优化数值计算,策略模式的编译期选择,静态多态和零开销抽象。

4. 现代替代: constexpr函数更易读易写,constexpr if简化条件分支(C++17),concepts约束模板参数(C++20),fold expression简化变参处理(C++17)。

// 编译期计算阶乘
template<int N>
struct Factorial {
    static constexpr int value = N * Factorial<N-1>::value;
};
template<>
struct Factorial<0> {
    static constexpr int value = 1;
};
constexpr int f5 = Factorial<5>::value;  // 120

// 类型选择
template<bool Cond, typename T, typename F>
struct If { using type = T; };
template<typename T, typename F>
struct If<false, T, F> { using type = F; };

// 现代方式:constexpr函数
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n-1);
}

7. 如何实现 C++ 中的类型萃取(Type Traits)?

1. 基本概念: 在编译期查询和操作类型信息,标准库提供std::is_integral、std::is_pointer等,使用模板特化实现,返回编译期常量或类型,用于泛型编程和SFINAE。

2. 实现方法: 主模板定义默认行为,特化模板处理特定类型,使用std::true_type和std::false_type表示布尔值,使用type成员表示类型,C++17的std::void_t简化实现。

3. 常用traits: is_same判断类型相同,is_base_of判断继承关系,remove_const移除const,add_pointer添加指针,enable_if条件启用,decay类型退化。

4. 使用场景: SFINAE选择重载函数,constexpr if编译期分支,概念约束模板参数,类型转换和适配,实现泛型算法的类型检查。

// 判断是否是指针
template<typename T>
struct is_pointer : std::false_type {};

template<typename T>
struct is_pointer<T*> : std::true_type {};

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++八股文全集 文章被收录于专栏

本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。

全部评论
重复了
点赞 回复 分享
发布于 03-04 14:44 广东
点赞 回复 分享
发布于 02-03 09:11 上海
太实用了!!!感谢大佬,你是我的神
点赞 回复 分享
发布于 01-20 18:23 湖南

相关推荐

评论
5
17
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务