《C++百炼成仙·修行题库》
——叶小凡的C++修炼手札·完整版
脚本大陆·千鹤派·藏经阁认证金丹宝典
杨逸飞 编著
序·叶老开示
叶沧澜(盘坐于混沌虚空,袖中飞出一卷玉简):
“小娃娃,C++修仙,非读几卷书便能成事。代码如剑,不磨不利;语法如丹,不炼不纯。今为师为你编纂这部《修行题库》,共七篇一百四十四关,上应天罡,下接地煞,乃千鹤派三千年道统之精粹。
刷题三忌:
· 一忌贪快——每题必亲手敲入灵纹(编译器),不可只凭目测。 · 二忌弃难——遇未定义行为、模板推导错误,正是悟道良机。 · 三忌抄答——答为死物,思为活泉。抄得答案,抄不得道心。
刷题三要:
· 一要逐行debug,观灵纹流转之轨迹。 · 二要举一反三,改条件、换类型、添特化。 · 三要勤于批注,将心得刻于玉简之侧。
此书每题后均有叶老点拨,乃老夫千年修行所悟。你且好生修习,待一百四十四关尽破,自可凝丹成婴,叩问化神。”
叶小凡(捧简如奉圣物):“弟子……肝脑涂地!”
第一篇·炼气期——七灵根筑基(共20题)
1.1 数据类型·灵根初显(原卷3题,增补拆为6题)
题1(填空题): 在C++中,sizeof(int)通常为______字节,sizeof(double)为______字节,sizeof(char)为______字节。 若在64位系统下,sizeof(int*)为______字节。
叶老点拨:整型灵根长短不一,然指针玉匣之大小,只与天地位宽有关,与所指何物无关。此乃指针第一义。
题2(选择题): 下列哪个数据类型不可表示负数? A. int B. signed int C. unsigned int D. float
答案:C
解析:unsigned为纯阳灵根,不识负阴。其余皆可正可负。
题3(改错题): 叶小凡想计算0.1 + 0.2并期望得到0.3,他写下了以下代码:
#include <iostream>
int main() {
float a = 0.1, b = 0.2;
if (a + b == 0.3)
std::cout << "相等" << std::endl;
else
std::cout << "不相等" << std::endl;
return 0;
}程序输出“不相等”。请指出错误原因并给出修正方案。
答案:浮点数二进制表示无法精确存储0.1、0.2,累加后产生微小误差,直接判等易失败。应使用容差比较:
#include <cmath>
if (std::abs((a + b) - 0.3) < 1e-6)叶老点拨:浮点灵根如流水,看似有形,实则无定。修士当容其微尘之谬。
题4(填空题): 整数100的字面量类型是______;整数100u的类型是______;整数100l的类型是______;整数100ul的类型是______;浮点数3.14的类型是______;浮点数3.14f的类型是______。
答案:int、unsigned int、long、unsigned long、double、float。
题5(选择题): 下列哪种类型转换会丢失数据? A. double → int B. int → double C. int → long D. unsigned int → int(值超出正范围)
答案:A、D
题6(写出输出):
unsigned int a = 1;
int b = -1;
std::cout << (a + b) << std::endl;答案:0(32位系统)。解析:混合运算时int转unsigned,-1成0xFFFFFFFF,加1得0x100000000,截断低32位为0。
1.2 运算符·灵气化合(原卷2题,增补拆为4题)
题7(写出输出):
int i = 1;
int a = i++ + ++i;
std::cout << a << std::endl;答案:未定义行为。同一表达式对i两次修改无顺序点,避如天劫。
题8(简答题): 请解释左值(lvalue)与右值(rvalue)的区别。
答案:左值有名字、可取址、持久;右值临时、无名、将亡。左值持身份,右值持价值。
题9(编程题): 使用位运算符,将int x的第3位(从0开始)设置为1,其他位不变。
x |= (1 << 3);题10(写出输出):
int x = 0b1100;
int y = 0b1010;
std::cout << (x & y) << std::endl;答案:8(0b1000)。
1.3 循环·往复之术(原卷1题,增补拆为2题)
题11(编程题): 用三种循环(for、while、do-while)分别计算1到100的和。
参考代码(略)。
题12(改错题):
int i = 0;
while (i < 10);
{
std::cout << i++;
}错误:while后多了分号,形成死循环。去掉分号。
1.4 sizeof·洞府丈量(增补2题)
题13(填空题): 对于空类class Empty{};,sizeof(Empty)通常为______(非0),这是为了______。
答案:1,为了确保不同对象有不同地址。
题14(简答题): 为什么C++中不允许sizeof(void)?
答案:void是不完全类型,代表“无”,没有大小。若已知大小,则非void。
1.5 auto·天道择型(增补1题)
题15(选择题):
auto a = 1;
auto b = 1.0;
auto c = 1.0f;
auto d = {1, 2, 3};d的类型是? A. int B. std::initializer_list<int> C. int[3] D. std::vector<int>
答案:B
1.6 decltype·以型推型(增补1题)
题16(填空题):
int x = 0;
decltype(x) y = 1; // y的类型是______
decltype((x)) z = y; // z的类型是______答案:int、int&
1.7 运算符优先级·法咒先后(增补1题)
题17(写出输出):
int a = 1, b = 2, c = 3;
int r = a++ + ++b * c--;答案:未定义行为(对c的读取与修改未定序)。实际环境可能得10,但不可依赖。
1.8 类型别名·更名诀(新增2题)
题18(填空题): C++11中定义别名模板使用关键字______,比typedef更强大。
答案:using
题19(编程题): 用using定义int_ptr为int*的别名。
using int_ptr = int*;1.9 constexpr·编译期恒常(新增1题)
题20(改错题):
const int square(int x) { return x * x; }
int arr[square(5)]; // 可能编译错误,为什么?答案:const函数不保证编译期求值,数组大小需要编译期常量。改为constexpr。
第二篇·筑基期——指针与洞府(共21题)
2.1 指针入门·天地坐标(原卷2题,增补拆为4题)
题21(填空题): 指针变量的本质是存储______。通过指针访问其所指对象,称为______,运算符为______。取变量地址的运算符为______。
答案:内存地址、解引用、*、&。
题22(改错题):
int* p;
*p = 10;错误:野指针,未初始化。应int* p = nullptr;或指向有效变量。
题23(填空题): const int* p:p是______,指向______。 int* const p:p是______,指向______。 const int* const p:两者皆______。
答案:指向常量的指针(可改指,不可改值)、指针常量(可改值,不可改指)、都不可改。
题24(改错题):
const int a = 10;
int* p = &a;错误:丢弃const限定。
2.2 数组·连续洞府(原卷2题,增补拆为3题)
题25(选择题): 对于数组int arr[5] = {1,2,3,4,5};,下列表达式错误的是: A. arr[2] B. *(arr + 2) C. arr++ D. &arr[0] + 1
答案:C(数组名是常量指针)。
题26(编程题): 不使用下标运算符[],仅用指针遍历二维数组int matrix[3][4]并输出所有元素。
参考代码:
int* p = &matrix[0][0];
for (int i = 0; i < 12; ++i, ++p)
std::cout << *p << " ";题27(写出输出):
int a[5] = {1,2,3,4,5};
int* p = a + 2;
std::cout << p[-1];答案:2(p[-1]等价于*(p-1))。
2.3 动态内存·堆海借府(原卷2题,增补拆为3题)
题28(填空题): C++中从堆区申请单个对象用关键字______,释放用______;申请对象数组用______,释放用______。若不释放已无用的堆内存,将导致______。
答案:new、delete、new[]、delete[]、内存泄漏。
题29(改错题):
int* p = new int(10);
delete p;
std::cout << *p;错误:野指针,delete后应置nullptr。
题30(改错题):
int* p = new int[10];
p += 5;
delete[] p;错误:delete[]必须传入new[]返回的原始地址,不能偏移。
2.4 多级指针·层层锁钥(增补1题)
题31(编程题): 定义三级指针,指向二级指针,二级指针指向一级指针,一级指针指向int变量,并最终通过三级指针修改变量的值。
参考代码:
int x = 5;
int* p1 = &x;
int** p2 = &p1;
int*** p3 = &p2;
***p3 = 10; // x == 102.5 函数指针·术法令牌(增补2题)
题32(填空题): 声明一个指向“参数为int, double,返回float”的函数指针pf: ______ pf;
答案:float (*pf)(int, double);
题33(编程题): 写一个函数calc,接受两个int和一个函数指针,返回运算结果。并用加法、乘法测试。
2.6 内存对齐·阵基安位(增补1题)
题34(填空题): alignas(16) int a;表示变量a按______字节对齐。alignof(int)返回int类型的对齐要求。
答案:16。
2.7 placement new·定点造府(增补2题)
题35(填空题): placement new的语法是new (______) Type(args);。它不分配内存,而是在______上构造对象。
答案:void*指针、已分配的内存。
题36(写出输出):
#include <new>
char buffer[sizeof(int)];
int* p = new(buffer) int(42);
std::cout << *p << std::endl;
p->~int();答案:42。
2.8 智能指针·护体灵光(筑基版,增补2题)
题37(选择题): 在C++11中,以下哪种智能指针不能用于数组? A. std::unique_ptr<int[]> B. std::shared_ptr<int[]>(C++17前不支持) C. std::unique_ptr<int> D. std::auto_ptr<int>
答案:B(C++11不支持,C++17部分支持,通常需自定义删除器)。
题38(编程题): 使用std::unique_ptr管理动态数组,存储10个整数并赋值0~9。
auto arr = std::make_unique<int[]>(10);
for (int i = 0; i < 10; ++i) arr[i] = i;2.9 内存泄漏检测·照妖镜(新增1题)
题39(简答题): 列举两种检测C++程序内存泄漏的方法。
答案:1. 使用Valgrind工具;2. 重载new/delete记录分配;3. Visual Studio的CRT调试堆函数。
2.10 指针与引用·别号之道(新增2题)
题40(选择题): 关于引用,下列说法正确的是: A. 引用必须初始化 B. 引用可以更改绑定 C. 引用占用内存(通常) D. 存在空引用
答案:A、C(引用底层用指针实现,占内存;但标准未规定,通常如此)。
题41(改错题):
int& r; // 错误:______答案:引用必须初始化。
第三篇·金丹期——类与对象(共20题)
3.1 封装·禁地之钥(原卷2题,增补拆为3题)
题42(简答题): private、protected、public三种访问修饰符的区别是什么?
答案:略。
题43(设计题): 设计一个class XiuZhe,包含私有属性姓名、年龄、灵根,提供公有set/get方法并校验。
参考代码:略。
题44(改错题):
class Test {
private:
int x;
};
Test t;
t.x = 5; // 错误:______答案:私有成员不可在类外访问。
3.2 构造·丹炉点火(原卷2题,增补拆为3题)
题45(改错题):
class Test {
private:
int& ref;
public:
Test(int x) { ref = x; }
};错误:引用成员必须在初始化列表中初始化。
题46(写出输出):
class Counter {
public:
static int count;
Counter() { ++count; }
~Counter() { --count; }
};
int Counter::count = 0;
Counter c1, c2;
std::cout << Counter::count;答案:2。
题47(编程题): 为String类添加拷贝构造函数和拷贝赋值运算符(深拷贝)。
3.3 友元·破壁之钥(原卷1题,增补拆为2题)
题48(简答题): 友元的优缺点。
答案:优点——灵活,可访问私有成员;缺点——破坏封装,增加耦合。
题49(编程题): 声明全局函数printXiuZhe为XiuZhe类的友元,使其能输出私有成员。
3.4 拷贝控制·三/五法则(增补2题)
题50(简答题): 什么是三/五法则?
答案:若自定义析构、拷贝构造、拷贝赋值中的任一,通常三者都需要自定义;C++11后加上移动构造、移动赋值,共五个。
题51(改错题):
class String {
char* data;
public:
String(const char* s) { /* 分配拷贝 */ }
~String() { delete[] data; }
// 缺少拷贝构造/赋值
};
String a = "hello";
String b = a; // 浅拷贝!双删!3.5 移动构造·窃丹术(增补1题)
题52(编程题): 为String类添加移动构造函数和移动赋值运算符,要求noexcept。
3.6 运算符重载·法器加持(增补2题)
题53(编程题): 实现class Complex,重载+、-、*、==、<<。
题54(写出输出):
class A {
public:
int x;
A(int x) : x(x) {}
A operator+(const A& rhs) const { return A(x + rhs.x); }
};
A a1(1), a2(2);
std::cout << (a1 + a2).x;答案:3。
3.7 explicit·隐式禁术(增补1题)
题55(改错题):
class C {
public:
explicit C(int) {}
};
void func(C) {}
func(10); // 错误:______答案:explicit禁止隐式转换,需func(C(10))。
3.8 mutable·金丹内府(增补2题)
题56(填空题): mutable关键字用于类的______成员,允许在______成员函数中修改它。
答案:非静态、const。
题57(写出输出):
class Counter {
mutable int cache = 0;
public:
int get() const { return ++cache; }
};
Counter c;
std::cout << c.get() << c.get();答案:12。
3.9 静态成员·宗门共业(增补2题)
题58(选择题): 静态成员函数不能: A. 访问静态成员变量 B. 访问非静态成员变量 C. 被派生类继承 D. 用类名调用
答案:B。
题59(编程题): 设计class Monastery记录弟子总数,提供静态函数getCount()。
3.10 内部类·府中有府(增补1题)
题60(简答题): 内部类能否访问外部类的私有成员?外部类能否访问内部类的私有成员?
答案:内部类是外部类的友元,可以访问外部类私有成员;外部类对内部类无私,不可访问内部类私有成员(除非显式友元)。
3.11 委托构造·一丹引二(新增1题)
题61(编程题): 使用C++11委托构造函数,令一个构造函数调用另一个构造函数。
第四篇·元婴期——继承与多态(共20题)
4.1 继承·血脉相承(原卷2题,增补拆为3题)
题62(选择题): 派生类继承了基类除____以外的所有成员。 A. 构造函数、析构函数、赋值运算符 B. 私有成员 C. 静态成员 D. 友元函数
答案:A。
题63(填空题): 派生类构造函数必须调用基类构造函数,若基类无默认构造,则必须在派生类的______中显式调用基类的______构造函数。
答案:初始化列表、带参。
题64(写出输出):
class A { public: A() { cout << "A"; } };
class B : public A { public: B() { cout << "B"; } };
int main() { B b; }答案:AB。
4.2 虚函数·剑同法异(原卷2题,增补拆为3题)
题65(写出输出):
class Base {
public:
virtual void show() { cout << "Base"; }
};
class Derived : public Base {
public:
void show() override { cout << "Derived"; }
};
int main() {
Base* p = new Derived();
p->show();
delete p;
}答案:Derived。
题66(改错题):
class Base {
public:
virtual void func() = 0;
};
Base b; // 错误:______答案:抽象类不可实例化。
题67(简答题): 虚函数表(vtable)存在哪里?每个对象都有虚表指针吗?
答案:虚表通常存于只读数据段,每个含虚函数的对象都有虚表指针(vptr)。
4.3 RTTI·辨其真身(原卷1题,增补拆为2题)
题68(编程题): 使用dynamic_cast安全地将基类指针转换为派生类指针。
题69(填空题): typeid(x).name()返回______,其头文件是______。
答案:类型名、<typeinfo>。
4.4 多重继承·一子承双(增补2题)
题70(选择题): 菱形继承(钻石问题)的解决方案是: A. 虚继承 B. 私有继承 C. 多重继承 D. 虚函数
答案:A。
题71(编程题): 用虚继承解决经典的菱形继承问题。
4.5 override/final·正名绝嗣(增补1题)
题72(填空题): override作用:;final作用在类上:,作用在虚函数上:______。
答案:显式标注覆盖,防止笔误;该类不可被继承;该虚函数不可被子类覆盖。
4.6 协变返回类型·剑变刃变(增补1题)
题73(选择题): 派生类覆盖基类虚函数时,返回类型可以不同,条件是: A. 返回类型必须是基类返回类型的派生类引用/指针 B. 必须完全相同 C. 任意 D. 必须有转换函数
答案:A。
4.7 类型转换操作符·化形诀(增补1题)
题74(编程题): 为Rational类定义到double的隐式转换操作符。
operator double() const { return (double)num / den; }4.8 异常安全·劫中护阵(增补2题)
题75(简答题): 异常安全三个级别。
答案:基本保证、强保证、不抛保证(noexcept)。
题76(改错题):
void f() {
int* p = new int(5);
g(); // 可能抛异常
delete p;
}改正:使用智能指针或try-catch。
4.9 纯虚析构·仙人遗愿(新增1题)
题77(编程题): 声明一个纯虚析构函数,并在类外提供定义。为什么纯虚析构必须定义?
答案:派生类析构时会调用基类析构,若无定义则链接错误。
4.10 抽象类·不可名状(新增1题)
题78(选择题): 下列哪项不是抽象类的特征? A. 不能实例化 B. 至少一个纯虚函数 C. 可以作为基类指针类型 D. 可以有纯虚析构函数
答案:D(可以有,但D不是特征,抽象类的特征是有纯虚函数)。
第五篇·化神期——模板与泛型(共21题)
5.1 函数模板·泛法归一(原卷2题,增补拆为3题)
题79(编程题): 写一个函数模板myMax,返回两个参数中的较大者。
题80(选择题): 关于模板函数,下列说法正确的是: A. 隐式实例化 B. 通常定义在头文件 C. 支持重载 D. 以上都对
答案:D。
题81(改错题):
template<typename T>
T add(T a, T b) { return a + b; }
int x = add(1, 2.5); // 错误:______答案:模板参数推导冲突,一个int一个double。应显式指定add<double>(1,2.5)或使用两个模板参数。
5.2 类模板·铸器图谱(原卷1题,增补拆为2题)
题82(编程题): 实现Stack类模板,支持push、pop、top、empty,底层用std::vector。
题83(填空题): 类模板的成员函数定义在类外时,语法为: template<typename T> 返回类型 类名<T>::函数名(参数)
5.3 模板特化·一人一门(原卷1题,增补拆为2题)
题84(填空题): 全特化语法:template<> class 类名<具体类型> {}; 偏特化语法:template<typename T> class 类名<T*> {};
题85(编程题): 为Stack<bool>提供全特化,使用位压缩存储。
5.4 STL·上古神器(原卷2题,增补拆为3题)
题86(简答题): 简述迭代器的作用及五类迭代器。
答案:略。
题87(编程题): 使用std::vector和std::sort,配合std::greater<int>()降序排序。
题88(写出输出):
std::vector<int> v{3,1,4};
auto it = v.begin();
std::cout << *it << *(it+1);答案:31。
5.5 可变参数模板·万剑诀(增补2题)
题89(编程题): 写可变参数模板print_all,打印所有参数。
题90(写出输出):
template<typename... Args>
auto sum(Args... args) { return (args + ...); }
std::cout << sum(1,2,3,4);答案:10。
5.6 SFINAE·替换失败非罪(增补2题)
题91(填空题): SFINAE全称______,核心思想______。
答案:Substitution Failure Is Not An Error,替换失败不是错误。
题92(选择题): 常用于SFINAE的工具是: A. std::enable_if B. std::is_same C. decltype D. 以上都是
答案:D。
5.7 type_traits·类型之镜(增补1题)
题93(编程题): 使用std::is_integral和enable_if,实现只接受整数类型的half函数。
5.8 模板模板参数·铸器之器(增补1题)
题94(填空题): 模板模板参数形如:template<template<typename> class Container> class X;,其中Container是一个______。
答案:模板名(未实例化的类模板)。
5.9 别名模板·更名诀(增补1题)
题95(改错题):
typedef T* Ptr<T>; // 错误:______答案:typedef不支持模板。应template<typename T> using Ptr = T*;
5.10 编译期断言·天道誓言(增补1题)
题96(编程题): 用static_assert在编译期检查类型是指针,否则报错。
5.11 概念(C++20)·新劫符(增补1题)
题97(填空题): C++20概念:定义Integral概念要求T为整型: template<typename T> concept Integral = ______;
答案:std::is_integral_v<T>
5.12 模板元编程·编译时演道(新增2题)
题98(编程题): 编写编译期阶乘Factorial<5>::value。
题99(编程题): 编写编译期斐波那契Fibonacci<10>::value。
第六篇·大乘期——现代C++(共21题)
6.1 右值引用·将亡之物(原卷3题,增补拆为4题)
题100(填空题): 右值引用符号______,主要用途______。
答案:&&、移动语义。
题101(写出输出):
void func(int&) { cout << "左值"; }
void func(int&&) { cout << "右值"; }
int a = 5;
func(a);
func(10);
func(std::move(a));答案:左值、右值、右值。
题102(编程题): 为vector<int>实现移动构造函数(noexcept)。
题103(选择题): std::move的作用是: A. 将对象移动到新位置 B. 将左值转为右值引用 C. 移动资源所有权 D. 以上都是
答案:B(std::move只是转换,不移动)。
6.2 智能指针·护体灵光(原卷2题,增补拆为3题)
题104(选择题): 下列智能指针中,独占所有权的是: A. shared_ptr B. unique_ptr C. weak_ptr D. auto_ptr
答案:B。
题105(改错题):
shared_ptr<int> sp1(new int(10));
weak_ptr<int> wp = sp1;
shared_ptr<int> sp2 = wp; // 错误:______答案:weak_ptr不能直接赋值给shared_ptr,应用wp.lock()。
题106(简答题): weak_ptr如何解决循环引用?
答案:weak_ptr不增加引用计数,打破环。
6.3 Lambda·无名元丹(原卷1题,增补拆为2题)
题107(编程题): 使用Lambda,将vector每个元素乘以捕获的factor。
题108(填空题): Lambda表达式[=](int x) mutable -> int { return x+1; }中,[=]表示______,mutable允许______。
答案:值捕获所有变量、修改捕获的副本。
6.4 并发·驭雷之术(原卷1题,增补拆为2题)
题109(简答题): std::thread如果主线程结束而子线程未结束,会发生什么?如何正确处理?
答案:程序调用std::terminate崩溃。应join()或detach()。
题110(编程题): 创建两个线程,分别执行函数print,并用互斥锁保护cout。
6.5 结构化绑定·分光化影(增补2题)
题111(编程题): 用结构化绑定遍历std::map<int, std::string>。
题112(写出输出):
std::tuple<int, double> t{1, 2.5};
auto [x, y] = t;
x = 10;
std::cout << std::get<0>(t);答案:1(绑定的是副本)。
6.6 if/switch with initializer·临阵布局(增补1题)
题113(改错题):
if (int x = foo(); x > 0) { /*...*/ }
std::cout << x; // 错误:______答案:x生命周期仅限于if。
6.7 filesystem·灵纹巡天(增补1题)
题114(编程题): 使用std::filesystem遍历当前目录下所有.cpp文件。
6.8 std::optional·或有或无(增补1题)
题115(编程题): 实现根据条件返回std::optional<int>,条件假返回空。
6.9 std::variant·多相玄珠(增补1题)
题116(选择题): std::variant<int, double>可以存储: A. 同时存储int和double B. 一次只存其中一种 C. 至少存储int D. 不能存储double
答案:B。
6.10 三路比较·天平衡器(增补1题)
题117(填空题): C++20operator<=>返回类型可能是______,头文件______。
答案:std::strong_ordering等,<compare>。
6.11 协程·元神出窍(增补1题)
题118(简答题): C++20协程关键字及其作用。
答案:co_await挂起,co_yield生成值,co_return返回。
6.12 并行算法·万剑齐发(增补1题)
题119(编程题): 用std::execution::par并行版std::for_each对vector平方。
6.13 原子操作·不坏金身(增补1题)
题120(改错题):
int counter = 0;
// 多线程 ++counter 不安全改正:用std::atomic<int>。
6.14 内存序·天机可测(增补1题)
题121(简答题): 简述memory_order_relaxed、acquire、release、acq_rel、seq_cst。
答案:略。
第七篇·混沌飞升——综合实战(共21题)
7.1 异派标准·协约碑模拟(原卷1题)
题122(综合设计题): 设计简化版“异派标准”框架:抽象基类Protocol,纯虚implement;三个派生类代表三宗;全局函数signContract(Protocol*)演示多态;用vector<Protocol*>存储并遍历。
参考代码:略。
7.2 内存池·堆田辟荒(原卷1题)
题123(高级编程题): 实现定长内存池,链表管理空闲块,支持allocate/deallocate。
7.3 单例模式·宗门唯一(增补1题)
题124(编程题): 线程安全的单例MonasteryMaster,使用C++11 Magic Static。
7.4 工厂模式·铸器阁(增补1题)
题125(设计题): 法器工厂ArtifactFactory,根据字符串返回不同法器unique_ptr。
7.5 观察者模式·阵旗传讯(增补1题)
题126(编程题): 实现简单事件系统,支持注册监听器和触发事件。
7.6 线程池·驭兽群(增补1题)
题127(高级编程题): 实现简易线程池,固定工作线程,接收std::function<void()>任务。
7.7 RAII实践·自动结界(增补1题)
题128(编程题): 实现FileGuard类,RAII管理FILE*,不可拷贝,可移动。
7.8 异派标准·终章补遗(增补1题)
题129(开放题): 为《异派标准》第二十四章(协程协定)写一份草案大纲。
7.9 沧澜碑·后之览者(增补1题)
题130(纪念题):
template<typename T>
void YeWuHen::daoTong(T&& future) {
static_assert(是否后辈_v<T>, "道统需后人来继");
future.覆盖();
}问题:这段代码体现了C++哪些精神?
答案:泛型、完美转发、静态断言、面向未来。道统非一人之业。
7.10 智能指针循环引用·阴阳锁魂(新增2题)
题131(简答题): 解释shared_ptr循环引用问题及weak_ptr解法。
题132(编程题): 构造一个父子双向引用的循环引用示例,并用weak_ptr破除。
7.11 CRTP·奇异递归模板(新增2题)
题133(填空题): CRTP全称______,典型形式:class Derived : public Base<Derived>。
答案:Curiously Recurring Template Pattern。
题134(编程题): 用CRTP实现静态多态,基类模板提供接口,派生类实现。
7.12 移动语义与完美转发·终极奥义(新增2题)
题135(改错题):
template<typename T>
void wrapper(T arg) {
foo(arg); // 无法转发右值属性
}改正:使用万能引用+完美转发:template<typename T> void wrapper(T&& arg) { foo(std::forward<T>(arg)); }
题136(编程题): 实现一个emplace_back风格的函数,向vector中完美转发参数构造对象。
7.13 类型萃取·识灵真诀(新增2题)
题137(编程题): 用std::is_same和std::enable_if实现函数重载:若T为整型则整除2,若为浮点则减半。
题138(写出输出):
std::cout << std::is_same<int, int32_t>::value;答案:1(true)。
7.14 constexpr与编译期计算·先天演卦(新增2题)
题139(编程题): 用constexpr函数计算字符串长度(编译期)。
题140(编程题): 用constexpr函数判断一个数是否为质数(编译期)。
7.15 C++20 Ranges·阵纹流转(新增2题)
题141(编程题): 使用C++20 Ranges,从vector<int>中筛选出偶数,并取其平方,然后输出。
题142(选择题): C++20 Ranges中,views::filter返回的是: A. 新容器 B. 视图(不拥有数据) C. 迭代器 D. 范围适配器
答案:B。
7.16 模块(Modules)·藏经新阁(新增1题)
题143(填空题): C++20模块导出关键______,导入关键______。
答案:export、import。
7.17 协程实战·元神分化(新增1题)
题144(编程题): 编写一个简单的生成器协程,yield返回整数序列0~9。
尾章·叶沧澜飞升批注
叶沧澜(立于混沌裂隙边,回望千鹤派):
“一百四十四关,天罡地煞尽破。小娃娃,你的指尖已浸透C++的剑气。
但为师须提醒你:习题集是渡海之筏,非彼岸之陆。
真正的修行,在真实项目的千沟万壑中,在生产环境的万丈灵压下,在与编译器斗智斗勇的每一个深夜。
代码无飞升,代码只在需要它的人手中。
去吧,莫要辜负这部题库,更莫要辜负你自己的道心。”
叶小凡(叩首):“弟子谨记!”
【全书终·道心长存】
编著附记
本书习题源自千鹤派藏经阁三千年历代弟子考核真题,经叶沧澜剑尊、叶无痕大乘、秦越守拙、林涛试剑、凌霜冰鉴,最终由叶小凡汇编成册。
凡一百四十四题,每题皆以血泪debug换来,愿后人惜之。
千鹤历四千八百二十四年·叶小凡·元婴大圆满·恭录
杨逸飞 谨识
【《C++百炼成仙·修行题库·完整版》·终】
(总题数:144题)