diff --git a/exercises/00_hello_world/main.cpp b/exercises/00_hello_world/main.cpp index 8866f3c15..2f5982d1b 100644 --- a/exercises/00_hello_world/main.cpp +++ b/exercises/00_hello_world/main.cpp @@ -1,11 +1,12 @@ #include "../exercise.h" - +using namespace std; // READ: std streams // READ: 流修饰符 // READ: format in cxx20 int main(int argc, char **argv) { // TODO: 在控制台输出 "Hello, InfiniTensor!" 并换行 - std::cout : "Hello, InfiniTensor!" + std::endl; + // std::cout : "Hello, InfiniTensor!" + std::endl; + std::cout<<"Hello, InfiniTensor!"< // THINK: 这个函数的两个 `static` 各自的作用是什么? + +// static修饰func函数,表示这个函数只在这个.cpp文件中可见 +// 其作用是防止重复定义,如果在另一个.cpp文件中定义了这个函数,加上static后,这两个函数就不会冲突,编译器不会发生“重复定义”错误 + +// static修饰static_局部变量,其作用是`静态存储期` +// 该变量**只初始化一次**,函数在运行结束后,变量不会被销毁,而是保存在内存中 static int func(int param) { static int static_ = param; // std::cout << "static_ = " << static_ << std::endl; @@ -10,10 +16,10 @@ static int func(int param) { int main(int argc, char **argv) { // TODO: 将下列 `?` 替换为正确的数字 - ASSERT(func(5) == ?, "static variable value incorrect"); - ASSERT(func(4) == ?, "static variable value incorrect"); - ASSERT(func(3) == ?, "static variable value incorrect"); - ASSERT(func(2) == ?, "static variable value incorrect"); - ASSERT(func(1) == ?, "static variable value incorrect"); + ASSERT(func(5) == 5, "static variable value incorrect"); + ASSERT(func(4) == 6, "static variable value incorrect"); + ASSERT(func(3) == 7, "static variable value incorrect"); + ASSERT(func(2) == 8, "static variable value incorrect"); + ASSERT(func(1) == 9, "static variable value incorrect"); return 0; } diff --git a/exercises/05_constexpr/main.cpp b/exercises/05_constexpr/main.cpp index d1db6c9d8..8755175ef 100644 --- a/exercises/05_constexpr/main.cpp +++ b/exercises/05_constexpr/main.cpp @@ -1,5 +1,7 @@ #include "../exercise.h" +// constexpr(constant expression),常量表达式 +// 告诉编译器,这是一个常量,需要在编译期间就要进行计算 constexpr unsigned long long fibonacci(int i) { switch (i) { case 0: @@ -19,8 +21,7 @@ int main(int argc, char **argv) { // TODO: 观察错误信息,修改一处,使代码编译运行 // PS: 编译运行,但是不一定能算出结果…… constexpr auto ANS_N = 90; - constexpr auto ANS = fibonacci(ANS_N); + auto ANS = fibonacci(ANS_N); std::cout << "fibonacci(" << ANS_N << ") = " << ANS << std::endl; - return 0; } diff --git a/exercises/06_array/main.cpp b/exercises/06_array/main.cpp index 61ed99ec0..e853e29f8 100644 --- a/exercises/06_array/main.cpp +++ b/exercises/06_array/main.cpp @@ -2,6 +2,7 @@ // READ: 数组 +// 数组定义 unsigned long long arr[90]{0, 1}; unsigned long long fibonacci(int i) { switch (i) { @@ -11,13 +12,15 @@ unsigned long long fibonacci(int i) { return 1; default: // TODO: 补全三目表达式缺失的部分 - return ? : (arr[i] = fibonacci(i - 1) + fibonacci(i - 2)); + return arr[i]!=0 ? arr[i] : (arr[i] = fibonacci(i - 1) + fibonacci(i - 2)); } } int main(int argc, char **argv) { // TODO: 为此 ASSERT 填写正确的值 - ASSERT(sizeof(arr) == ?, "sizeof array is size of all its elements"); + // std::cout< static unsigned long long fibonacci(int i) { // TODO: 为缓存设置正确的初始值 - static unsigned long long cache[96], cached; + static unsigned long long cache[96]{0,1}, cached=2; // TODO: 设置正确的循环条件 - for (; false; ++cached) { + for (; cached<96; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; diff --git a/exercises/08_pointer/main.cpp b/exercises/08_pointer/main.cpp index ba37173f5..754d2d816 100644 --- a/exercises/08_pointer/main.cpp +++ b/exercises/08_pointer/main.cpp @@ -1,10 +1,20 @@ #include "../exercise.h" // READ: 数组向指针退化 +//bool is_fibonacci(int ptr[], int len, int stride) bool is_fibonacci(int *ptr, int len, int stride) { ASSERT(len >= 3, "`len` should be at least 3"); // TODO: 编写代码判断从 ptr 开始,每 stride 个元素取 1 个元素,组成长度为 n 的数列是否满足 // arr[i + 2] = arr[i] + arr[i + 1] + for(int i = 0;i +// enum(枚举)是一种用户自定义的数据类型,用于为一组`整数常量`分配好听的名字。使用枚举可以让代码更具可读性和可维护性。 + // `enum` 是 C 的兼容类型,本质上其对应类型的常量。 // 在 `enum` 中定义标识符等价于定义 constexpr 常量, // 这些标识符不需要前缀,可以直接引用。 // 因此 `enum` 定义会污染命名空间。 + +// 不限定作用域枚举,不推荐作法 +// 可以实现隐式转换:int x =Red enum ColorEnum : unsigned char { COLOR_RED = 31, COLOR_GREEN, @@ -16,6 +21,10 @@ enum ColorEnum : unsigned char { // 有作用域枚举型是 C++ 引入的类型安全枚举。 // 其内部标识符需要带前缀引用,如 `Color::Red`。 // 作用域枚举型可以避免命名空间污染,并提供类型安全保证。 + +// 限定作用域枚举,推荐做法 +// 使用时必须带上类名(作用域) +// TrafficLight s = TrafficLight::RED; enum class Color : int { Red = COLOR_RED, Green, @@ -30,6 +39,9 @@ ColorEnum convert_by_pun(Color c) { // 但这种写法实际上仅在 C 语言良定义,在 C++ 中是未定义行为。 // 这是比较少见的 C++ 不与 C 保持兼容的特性。 // READ: 类型双关 + + //union(联合体/共用体)是 C++ 中一种特殊的类类型。它最显著的特征是:所有成员共享同一块内存地址 + //但在同一时刻只能使用其中的一个成员,这就意味着数据会被覆盖,是一种极端节省内存的写法 union TypePun { ColorEnum e; Color c; @@ -37,7 +49,7 @@ ColorEnum convert_by_pun(Color c) { TypePun pun; // TODO: 补全类型双关转换 - + pun.c = c;//c值写入,e值被覆盖 return pun.e; } diff --git a/exercises/10_trivial/main.cpp b/exercises/10_trivial/main.cpp index 6ba23e48e..fdbc6f163 100644 --- a/exercises/10_trivial/main.cpp +++ b/exercises/10_trivial/main.cpp @@ -8,18 +8,27 @@ struct FibonacciCache { }; // TODO: 实现正确的缓存优化斐波那契计算 -static unsigned long long fibonacci(FibonacciCache &cache, int i) { - for (; false; ++cached) { - cache[cached] = cache[cached - 1] + cache[cached - 2]; +// static unsigned long long fibonacci(FibonacciCache &cache, int i) { +// for (; false; ++cached) { +// cache[cached] = cache[cached - 1] + cache[cached - 2]; +// } +// return cache.cache[i]; +// } +static unsigned long long fibonacci(FibonacciCache &cache, int i){ + if(i>=16){ + return 0; + } + for(;cache.cached<=i;++cache.cached){ + cache.cache[cache.cached]=cache.cache[cache.cached-1]+cache.cache[cache.cached-2]; } return cache.cache[i]; -} +} int main(int argc, char **argv) { // TODO: 初始化缓存结构体,使计算正确 // NOTICE: C/C++ 中,读取未初始化的变量(包括结构体变量)是未定义行为 // READ: 初始化的各种写法 - FibonacciCache fib; + FibonacciCache fib{{0,1},2}; ASSERT(fibonacci(fib, 10) == 55, "fibonacci(10) should be 55"); std::cout << "fibonacci(10) = " << fibonacci(fib, 10) << std::endl; return 0; diff --git a/exercises/11_method/main.cpp b/exercises/11_method/main.cpp index 0e08e0a36..8686d89fa 100644 --- a/exercises/11_method/main.cpp +++ b/exercises/11_method/main.cpp @@ -6,16 +6,19 @@ struct Fibonacci { // TODO: 实现正确的缓存优化斐波那契计算 unsigned long long get(int i) { - for (; false; ++cached) { - cache[cached] = cache[cached - 1] + cache[cached - 2]; + if (i>=128){ + return 0; } - return cache[i]; + for (; this->cached<=i; ++this->cached) { + this->cache[this->cached] = this->cache[this->cached - 1] + this->cache[this->cached - 2]; + } + return this->cache[i]; } }; int main(int argc, char **argv) { // TODO: 初始化缓存结构体,使计算正确 - Fibonacci fib; + Fibonacci fib{{0,1},2}; ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55"); std::cout << "fibonacci(10) = " << fib.get(10) << std::endl; return 0; diff --git a/exercises/12_method_const/main.cpp b/exercises/12_method_const/main.cpp index 5521be4da..a0cea179e 100644 --- a/exercises/12_method_const/main.cpp +++ b/exercises/12_method_const/main.cpp @@ -5,11 +5,20 @@ struct Fibonacci { int numbers[11]; // TODO: 修改方法签名和实现,使测试通过 - int get(int i) { + // int get(int i) { + // } + int get(int i) const { + if (i<0 || i>=11) + { + return 0; + } + + return numbers[i]; } }; int main(int argc, char **argv) { + //关键字 constexpr 意味着对象 FIB 是编译期常量,它隐含了 const 属性。在 C++ 中,const 对象只能调用 const 成员函数。 Fibonacci constexpr FIB{{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55}}; ASSERT(FIB.get(10) == 55, "fibonacci(10) should be 55"); std::cout << "fibonacci(10) = " << FIB.get(10) << std::endl; diff --git a/exercises/13_class/main.cpp b/exercises/13_class/main.cpp index 9afa98c5b..fca2cbcb7 100644 --- a/exercises/13_class/main.cpp +++ b/exercises/13_class/main.cpp @@ -9,17 +9,23 @@ // 因此必须提供构造器来初始化字段。 // READ: 构造器 class Fibonacci { + //size_t 无符号整数类型 size_t cache[16]; int cached; public: // TODO: 实现构造器 // Fibonacci() + Fibonacci(){ + this->cache[0]=0; + this->cache[1]=1; + this->cached=2; + } // TODO: 实现正确的缓存优化斐波那契计算 size_t get(int i) { - for (; false; ++cached) { - cache[cached] = cache[cached - 1] + cache[cached - 2]; + for (; this->cached <= i; ++this->cached) { + this->cache[this->cached] = this->cache[this->cached - 1] + this->cache[this->cached - 2]; } return cache[i]; } diff --git a/exercises/14_class_destruct/main.cpp b/exercises/14_class_destruct/main.cpp index 42150e8ca..846c45b9b 100644 --- a/exercises/14_class_destruct/main.cpp +++ b/exercises/14_class_destruct/main.cpp @@ -11,15 +11,24 @@ class DynFibonacci { public: // TODO: 实现动态设置容量的构造器 - DynFibonacci(int capacity): cache(new ?), cached(?) {} + // cache = new size_t[capacity];动态初始化数组 + // 成员初始化列表(Member Initializer List):构造函数:函数名(参数) : 成员1(初始化), 成员2(初始化) { 函数体 } + DynFibonacci(int capacity): cache(new size_t[capacity]), cached(2) { + cache[0] = 0; + cache[1] = 1; + } // TODO: 实现析构器,释放缓存空间 - ~DynFibonacci(); + ~DynFibonacci() { + // 使用 delete[]:因为 cache 是用 new[] 分配的数组 + // 如果用 delete cache(没有 []),会导致未定义行为 + delete[] cache; + } // TODO: 实现正确的缓存优化斐波那契计算 size_t get(int i) { - for (; false; ++cached) { - cache[cached] = cache[cached - 1] + cache[cached - 2]; + for (; this->cached <= i; ++this->cached) { + this->cache[this->cached] = this->cache[this->cached - 1] + this->cache[this->cached - 2]; } return cache[i]; } diff --git a/exercises/15_class_clone/main.cpp b/exercises/15_class_clone/main.cpp index f74b70391..17dd8b344 100644 --- a/exercises/15_class_clone/main.cpp +++ b/exercises/15_class_clone/main.cpp @@ -7,21 +7,32 @@ class DynFibonacci { size_t *cache; int cached; - + int capacity;//记录容量 public: // TODO: 实现动态设置容量的构造器 - DynFibonacci(int capacity): cache(new ?), cached(?) {} + // DynFibonacci(int capacity): cache(new ?), cached(?) {} + DynFibonacci(int capacity): cache(new size_t[capacity]), cached(2),capacity(capacity) { + cache[0] = 0; + cache[1] = 1; + } // TODO: 实现复制构造器 - DynFibonacci(DynFibonacci const &) = delete; + DynFibonacci(DynFibonacci const &other) : cache(new size_t[other.capacity]), cached(other.cached), capacity(other.capacity) { + //复制 cache + for (int i = 0; i < other.cached; ++i) { + this->cache[i] = other.cache[i]; + } + }; // TODO: 实现析构器,释放缓存空间 - ~DynFibonacci(); + ~DynFibonacci(){ + delete[] cache; + } // TODO: 实现正确的缓存优化斐波那契计算 size_t get(int i) { - for (; false; ++cached) { - cache[cached] = cache[cached - 1] + cache[cached - 2]; + for (; this->cached <= i; ++this->cached) { + this->cache[this->cached] = this->cache[this->cached - 1] + this->cache[this->cached - 2]; } return cache[i]; } diff --git a/exercises/16_class_move/main.cpp b/exercises/16_class_move/main.cpp index 8d2c421da..50920f54c 100644 --- a/exercises/16_class_move/main.cpp +++ b/exercises/16_class_move/main.cpp @@ -9,27 +9,62 @@ // READ: 移动赋值 // READ: 运算符重载 +// 左值 (Lvalue) vs 右值 (Rvalue): +// - 左值:有名字、有固定地址的对象(如变量名 fib)。可以取址&。 +// - 右值:临时的、即将销毁的对象(如 std::move(fib) 的返回值,或临时计算结果)。不能取址&。 +// - 右值引用(Rvalue Reference) 是 C++11 引入的一种新引用类型,专门用来绑定到临时对象(右值)上。 +// 移动语义 (Move Semantics): +// - 核心在于“接管”资源而非“复制”资源。对于动态分配的内存,移动只需交换指针。 +// - 核心思想:“剪切 + 粘贴” 而不是 “复制 + 粘贴”。 +// 换言之,移动语义意味着“接管”资源而非“复制”资源。 +// noexcept: +// - 移动构造和移动赋值通常标记为 noexcept,告知编译器此操作不会抛出异常, +// 这对于 std::vector 等容器在扩容时的性能优化至关重要。 class DynFibonacci { size_t *cache; int cached; public: // TODO: 实现动态设置容量的构造器 - DynFibonacci(int capacity): cache(new ?), cached(?) {} + DynFibonacci(int capacity): cache(new size_t[capacity]), cached(2) { + if (capacity>0) cache[0] = 0; + if (capacity>1) cache[1] = 1; + } // TODO: 实现移动构造器 - DynFibonacci(DynFibonacci &&) noexcept = delete; + // 通过右值引用(&&),接管 other 的资源,将other置于有效但未定义状态(指针置空) + DynFibonacci(DynFibonacci && other) noexcept : cache(other.cache), cached(other.cached) { + // 断开对原对象的内存引用 + other.cache = nullptr; + other.cached = 0; + } // TODO: 实现移动赋值 // NOTICE: ⚠ 注意移动到自身问题 ⚠ - DynFibonacci &operator=(DynFibonacci &&) noexcept = delete; + // 移动赋值需要先释放自己的资源,再接管别人的资源 + DynFibonacci &operator=(DynFibonacci &&other) noexcept { + //自赋值检查,防止fib=std::move(fib)导致资源提取释放 + if(this!= &other){ + //1.释放旧资源 + delete[] cache; + //2.接管新资源 + cache = other.cache; + cached = other.cached; + //3.断开对原对象的内存引用 + other.cache = nullptr; + other.cached = 0; + } + return *this; + } // TODO: 实现析构器,释放缓存空间 - ~DynFibonacci(); + ~DynFibonacci(){ + delete[] cache; + } // TODO: 实现正确的缓存优化斐波那契计算 size_t operator[](int i) { - for (; false; ++cached) { + for (; cached <= i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; diff --git a/exercises/17_class_derive/main.cpp b/exercises/17_class_derive/main.cpp index 819ae72fc..3cd299646 100644 --- a/exercises/17_class_derive/main.cpp +++ b/exercises/17_class_derive/main.cpp @@ -30,9 +30,12 @@ struct A { std::cout << ++i << ". " << "~A(" << a << ')' << std::endl; } }; +// `:public`:表示继承public和protected对象,权限不变 +// `:private`:表示继承public和protected对象,权限变为private +// `:protected`:表示继承public和protected对象,权限变为protected struct B : public A { X x; - + B(int b) : A(1), x(b) { std::cout << ++i << ". " << "B(" << a << ", X(" << x.x << "))" << std::endl; } @@ -50,9 +53,9 @@ int main(int argc, char **argv) { B b = B(3); // TODO: 补全三个类型的大小 - static_assert(sizeof(X) == ?, "There is an int in X"); - static_assert(sizeof(A) == ?, "There is an int in A"); - static_assert(sizeof(B) == ?, "B is an A with an X"); + static_assert(sizeof(X) == 4, "There is an int in X"); + static_assert(sizeof(A) == 4, "There is an int in A"); + static_assert(sizeof(B) == 8, "B is an A with an X"); i = 0; std::cout << std::endl diff --git a/exercises/18_class_virtual/main.cpp b/exercises/18_class_virtual/main.cpp index ac6382413..8603652cf 100644 --- a/exercises/18_class_virtual/main.cpp +++ b/exercises/18_class_virtual/main.cpp @@ -1,7 +1,34 @@ #include "../exercise.h" // READ: 虚函数 +// 虚函数(Virtual Function) 是实现多态(Polymorphism)的核心机制。 +// - 它允许你在派生类(子类)中重写基类(父类)定义的函数 +// - 并确保通过基类指针或引用调用该函数时,实际执行的是子类中的版本。 +// <----> +// 虚函数: +// - 在基类中使用关键字 virtual 声明的函数称为虚函数。 +// - 在派生类使用override 关键字用于明确表示重写 +// class Base { +// public: +// virtual void show() { +// cout << "这是基类的 show 函数" << endl; +// } +// }; +// class Derived : public Base { +// public: +// void show() override { // override 关键字用于明确表示重写(C++11) +// cout << "这是派生类的 show 函数" << endl; +// } +// }; +// <----> +// final 关键字有两个主要用途:禁止虚函数被进一步重写 以及 禁止类被继承。 +// - 当在派生类中将一个虚函数标记为 final 时,任何尝试在更深层的子类中重写该函数的行为都会导致编译错误。 +// - 如果将 final 放在类名后面,则表示该类是“最终类”,不允许任何类继承它。 +// 核心口诀: +// - 虚函数看对象(实际是谁就调谁)。 +// - 普通函数看类型(声明是谁就调谁)。 +// - final 锁死子类(不影响父类引用调自己)。 struct A { virtual char virtual_name() const { return 'A'; @@ -42,38 +69,38 @@ int main(int argc, char **argv) { C c; D d; - ASSERT(a.virtual_name() == '?', MSG); - ASSERT(b.virtual_name() == '?', MSG); - ASSERT(c.virtual_name() == '?', MSG); - ASSERT(d.virtual_name() == '?', MSG); - ASSERT(a.direct_name() == '?', MSG); - ASSERT(b.direct_name() == '?', MSG); - ASSERT(c.direct_name() == '?', MSG); - ASSERT(d.direct_name() == '?', MSG); + ASSERT(a.virtual_name() == 'A', MSG); + ASSERT(b.virtual_name() == 'B', MSG); + ASSERT(c.virtual_name() == 'C', MSG); + ASSERT(d.virtual_name() == 'C', MSG); + ASSERT(a.direct_name() == 'A', MSG); + ASSERT(b.direct_name() == 'B', MSG); + ASSERT(c.direct_name() == 'C', MSG); + ASSERT(d.direct_name() == 'D', MSG); A &rab = b; B &rbc = c; C &rcd = d; - ASSERT(rab.virtual_name() == '?', MSG); - ASSERT(rbc.virtual_name() == '?', MSG); - ASSERT(rcd.virtual_name() == '?', MSG); - ASSERT(rab.direct_name() == '?', MSG); - ASSERT(rbc.direct_name() == '?', MSG); - ASSERT(rcd.direct_name() == '?', MSG); + ASSERT(rab.virtual_name() == 'B', MSG); + ASSERT(rbc.virtual_name() == 'C', MSG); + ASSERT(rcd.virtual_name() == 'C', MSG); + ASSERT(rab.direct_name() == 'A', MSG); + ASSERT(rbc.direct_name() == 'B', MSG); + ASSERT(rcd.direct_name() == 'C', MSG); A &rac = c; B &rbd = d; - ASSERT(rac.virtual_name() == '?', MSG); - ASSERT(rbd.virtual_name() == '?', MSG); - ASSERT(rac.direct_name() == '?', MSG); - ASSERT(rbd.direct_name() == '?', MSG); + ASSERT(rac.virtual_name() == 'C', MSG); + ASSERT(rbd.virtual_name() == 'C', MSG); + ASSERT(rac.direct_name() == 'A', MSG); + ASSERT(rbd.direct_name() == 'B', MSG); A &rad = d; - ASSERT(rad.virtual_name() == '?', MSG); - ASSERT(rad.direct_name() == '?', MSG); + ASSERT(rad.virtual_name() == 'C', MSG); + ASSERT(rad.direct_name() == 'A', MSG); return 0; } diff --git a/exercises/19_class_virtual_destruct/main.cpp b/exercises/19_class_virtual_destruct/main.cpp index cdd54f74f..c21a0e05d 100644 --- a/exercises/19_class_virtual_destruct/main.cpp +++ b/exercises/19_class_virtual_destruct/main.cpp @@ -5,12 +5,15 @@ struct A { // TODO: 正确初始化静态字段 - static int num_a = 0; + // 使用 inline static 在类内完成初始化 + // C++17 及以上版本支持 inline static 字段初始化 + inline static int num_a = 0; A() { ++num_a; } - ~A() { + ///虚析构函数,确保通过基类指针删除派生类对象时,派生类的析构函数也会被调用 + virtual ~A() { --num_a; } @@ -20,13 +23,14 @@ struct A { }; struct B final : public A { // TODO: 正确初始化静态字段 - static int num_b = 0; + inline static int num_b = 0; B() { ++num_b; } ~B() { --num_b; + } char name() const final { @@ -37,10 +41,11 @@ struct B final : public A { int main(int argc, char **argv) { auto a = new A; auto b = new B; - ASSERT(A::num_a == ?, "Fill in the correct value for A::num_a"); - ASSERT(B::num_b == ?, "Fill in the correct value for B::num_b"); - ASSERT(a->name() == '?', "Fill in the correct value for a->name()"); - ASSERT(b->name() == '?', "Fill in the correct value for b->name()"); + // B 继承自 A,因此创建 B 对象时也会调用 A 的构造函数 + ASSERT(A::num_a == 2, "Fill in the correct value for A::num_a"); + ASSERT(B::num_b == 1, "Fill in the correct value for B::num_b"); + ASSERT(a->name() == 'A', "Fill in the correct value for a->name()"); + ASSERT(b->name() == 'B', "Fill in the correct value for b->name()"); delete a; delete b; @@ -48,13 +53,16 @@ int main(int argc, char **argv) { ASSERT(B::num_b == 0, "Every B was destroyed"); A *ab = new B;// 派生类指针可以随意转换为基类指针 - ASSERT(A::num_a == ?, "Fill in the correct value for A::num_a"); - ASSERT(B::num_b == ?, "Fill in the correct value for B::num_b"); - ASSERT(ab->name() == '?', "Fill in the correct value for ab->name()"); + ASSERT(A::num_a == 1, "Fill in the correct value for A::num_a"); + ASSERT(B::num_b == 1, "Fill in the correct value for B::num_b"); + ASSERT(ab->name() == 'B', "Fill in the correct value for ab->name()"); // TODO: 基类指针无法随意转换为派生类指针,补全正确的转换语句 - B &bb = *ab; - ASSERT(bb.name() == '?', "Fill in the correct value for bb->name()"); + // 1. 使用 dynamic_cast 进行安全的向下转换(推荐使用)(前提是基类有虚函数) + // 2. 使用 static_cast 进行不安全的向下转换(速度快,但不安全)( + // B &bb = *ab; + B &bb = dynamic_cast(*ab); + ASSERT(bb.name() == 'B', "Fill in the correct value for bb->name()"); // TODO: ---- 以下代码不要修改,通过改正类定义解决编译问题 ---- delete ab;// 通过指针可以删除指向的对象,即使是多态对象 diff --git a/exercises/20_function_template/main.cpp b/exercises/20_function_template/main.cpp index cb6d978d3..31daed851 100644 --- a/exercises/20_function_template/main.cpp +++ b/exercises/20_function_template/main.cpp @@ -1,8 +1,16 @@ #include "../exercise.h" // READ: 函数模板 +// 函数模板--`template`, +// - 函数模板就像是一个“模具”或“蓝图”。 +// - 不需要为 int、float 或 double 分别编写逻辑相同的函数 +// - // T1 和 T2 可以是不同类型`template ` // TODO: 将这个函数模板化 -int plus(int a, int b) { +// int plus(int a, int b) { +// return a + b; +// } +template +T plus(T a, T b) { return a + b; } @@ -14,7 +22,8 @@ int main(int argc, char **argv) { ASSERT(plus(1.25f, 2.5f) == 3.75f, "Plus two float"); ASSERT(plus(1.25, 2.5) == 3.75, "Plus two double"); // TODO: 修改判断条件使测试通过 - ASSERT(plus(0.1, 0.2) == 0.3, "How to make this pass?"); + // 浮点数精度问题,不能直接用 == 判断 + ASSERT(std::abs(plus(0.1, 0.2) - 0.3) < 1e-9, "How to make this pass?"); return 0; } diff --git a/exercises/21_runtime_datatype/main.cpp b/exercises/21_runtime_datatype/main.cpp index 9c4bf376a..3339a2dc4 100644 --- a/exercises/21_runtime_datatype/main.cpp +++ b/exercises/21_runtime_datatype/main.cpp @@ -18,13 +18,27 @@ struct TaggedUnion { }; // TODO: 将这个函数模板化用于 sigmoid_dyn -float sigmoid(float x) { +// float sigmoid(float x) { +// return 1 / (1 + std::exp(-x)); +// } +template +T sigmoid(T x){ return 1 / (1 + std::exp(-x)); } TaggedUnion sigmoid_dyn(TaggedUnion x) { TaggedUnion ans{x.type}; // TODO: 根据 type 调用 sigmoid + // 让函数能同时处理 float 和 double + switch (x.type) + { + case DataType::Float: + ans.f = sigmoid(x.f); + break; + case DataType::Double: + ans.d = sigmoid(x.d); + break; + } return ans; } diff --git a/exercises/22_class_template/main.cpp b/exercises/22_class_template/main.cpp index d4985d904..1d2f1b003 100644 --- a/exercises/22_class_template/main.cpp +++ b/exercises/22_class_template/main.cpp @@ -1,7 +1,7 @@ #include "../exercise.h" #include // READ: 类模板 - +// 类模板(Class Template) 是泛型编程的核心工具。它允许我们编写一个通用的类,而不必为每种数据类型都重写一遍代码。 template struct Tensor4D { unsigned int shape[4]; @@ -10,6 +10,10 @@ struct Tensor4D { Tensor4D(unsigned int const shape_[4], T const *data_) { unsigned int size = 1; // TODO: 填入正确的 shape 并计算 size + for (int i = 0; i < 4; i++) { + shape[i] = shape_[i]; + size *= shape[i]; + } data = new T[size]; std::memcpy(data, data_, size * sizeof(T)); } @@ -28,10 +32,47 @@ struct Tensor4D { // 则 `this` 与 `others` 相加时,3 个形状为 `[1, 2, 1, 4]` 的子张量各自与 `others` 对应项相加。 Tensor4D &operator+=(Tensor4D const &others) { // TODO: 实现单向广播的加法 + // 1.预先计算others 的 strides (步长),用于将 (n,c,h,w) 坐标转换为线性索引 + // 线性索引 = n * stride_0 + c * stride_1 + h * stride_2 + w * stride_3 + unsigned int o_stride3=1; + unsigned int o_stride2=others.shape[3]; + unsigned int o_stride1=o_stride2*others.shape[2]; + unsigned int o_stride0=o_stride1*others.shape[1]; + //// 使用指针直接遍历 this->data,避免重复计算 this 的线性索引 + T* current_ptr = this->data; + // 4层循环遍历 this 的所有维度 + for (unsigned int n = 0; n < shape[0]; ++n) { + // 如果 others 在该维度长度为1,则索引固定为0(广播),否则跟随 n + unsigned int n_idx = (others.shape[0] == 1) ? 0 : n; + + for (unsigned int c = 0; c < shape[1]; ++c) { + unsigned int c_idx = (others.shape[1] == 1) ? 0 : c; + + for (unsigned int h = 0; h < shape[2]; ++h) { + unsigned int h_idx = (others.shape[2] == 1) ? 0 : h; + + for (unsigned int w = 0; w < shape[3]; ++w) { + unsigned int w_idx = (others.shape[3] == 1) ? 0 : w; + // 计算 others 中的线性偏移量 + unsigned int others_offset = + n_idx * o_stride0 + + c_idx * o_stride1 + + h_idx * o_stride2 + + w_idx * o_stride3; + // 执行加法 + *current_ptr += others.data[others_offset]; + + // 移动到 this 的下一个元素 + ++current_ptr; + } + } + } + } return *this; } }; + // ---- 不要修改以下代码 ---- int main(int argc, char **argv) { { diff --git a/exercises/23_template_const/main.cpp b/exercises/23_template_const/main.cpp index e0105e168..3e9e0f690 100644 --- a/exercises/23_template_const/main.cpp +++ b/exercises/23_template_const/main.cpp @@ -11,6 +11,11 @@ struct Tensor { Tensor(unsigned int const shape_[N]) { unsigned int size = 1; // TODO: 填入正确的 shape 并计算 size + for (unsigned int i = 0; i < N; i++) + { + shape[i] = shape_[i]; + size *= shape[i]; + } data = new T[size]; std::memset(data, 0, size * sizeof(T)); } @@ -35,6 +40,7 @@ struct Tensor { for (unsigned int i = 0; i < N; ++i) { ASSERT(indices[i] < shape[i], "Invalid index"); // TODO: 计算 index + index = index * shape[i] + indices[i]; } return index; } diff --git a/exercises/24_std_array/main.cpp b/exercises/24_std_array/main.cpp index c29718d9d..19d748fd7 100644 --- a/exercises/24_std_array/main.cpp +++ b/exercises/24_std_array/main.cpp @@ -4,25 +4,43 @@ // READ: std::array +// std::array是对 C 语言风格数组(如 int arr[5])的现代化封装。 +// - 既保留了原生数组的高性能(零开销) +// - 又提供了类似 STL 容器(如 std::vector)的安全性和便利性接口。 +// 1.基本语法,需要包含头文件 。 +// - std::array myArray = {1, 2, 3, 4, 5}; +// - 第一个模板参数 int 是数据类型,第二个模板参数 5 是数组大小(必须是编译期常量)。 +// 2.为什么要使用 std::array? +// - std::array 是一个对象,包含长度消息和数据,不会退化为指针 +// - std::array 支持直接赋值,只要类型和大小相同 +// - std::array 安全性高,提供了 .at() 方法,会进行边界检查。如果越界,会抛出异常 +// - std::array STL兼容性强,提供了迭代器(begin(), end()),可以完美配合 std::sort, std::for_each 等标准算法使用。 +// 3. 主要特性 +// - 内存分配: 与 C 数组一样,数据通常存储在栈(Stack)上(除非它是全局变量或被 new 出来的)。这意味着没有动态内存分配(堆内存)的开销,速度极快。 +// - 固定大小: 大小在编译时必须确定,运行时不能改变(不能像 vector 那样 push_back)。 +// - 零开销: 在优化开启的情况下,std::array 的性能与 C 风格数组完全一致。 + +// std::memcmp (Memory Compare) 是用来比较两块内存区域的内容是否完全一致的函数 // TODO: 将下列 `?` 替换为正确的代码 int main(int argc, char **argv) { { std::array arr{{1, 2, 3, 4, 5}}; - ASSERT(arr.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(arr) == ?, "Fill in the correct value."); + ASSERT(arr.size() == 5, "Fill in the correct value.");//数组大小 + ASSERT(sizeof(arr) == 20, "Fill in the correct value.");//int 的大小为 4 int ans[]{1, 2, 3, 4, 5}; - ASSERT(std::memcmp(arr.?, ans, ?) == 0, "Fill in the correct values."); + //比较arr.data 和 ans,长度为 sizeof(ans) + ASSERT(std::memcmp(arr.data(), ans, sizeof(ans)) == 0, "Fill in the correct values."); } { std::array arr; - ASSERT(arr.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(arr) == ?, "Fill in the correct value."); + ASSERT(arr.size() == 8, "Fill in the correct value."); + ASSERT(sizeof(arr) == 64, "Fill in the correct value.");//double 的大小为 8 } { std::array arr{"Hello, InfiniTensor!"}; - ASSERT(arr.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(arr) == ?, "Fill in the correct value."); - ASSERT(std::strcmp(arr.?, "Hello, InfiniTensor!") == 0, "Fill in the correct value."); + ASSERT(arr.size() == 21, "Fill in the correct value."); + ASSERT(sizeof(arr) == 21, "Fill in the correct value.");//char 的大小为 1 + ASSERT(std::strcmp(arr.data(), "Hello, InfiniTensor!") == 0, "Fill in the correct value."); } return 0; } diff --git a/exercises/25_std_vector/main.cpp b/exercises/25_std_vector/main.cpp index f9e41bb78..29bcbcf94 100644 --- a/exercises/25_std_vector/main.cpp +++ b/exercises/25_std_vector/main.cpp @@ -3,86 +3,95 @@ #include // READ: std::vector - +// vector 是一种序列容器,它允许你在运行时动态地插入和删除元素。需要使用头文件 。 // TODO: 将下列 `?` 替换为正确的代码 int main(int argc, char **argv) { { std::vector vec{1, 2, 3, 4, 5}; - ASSERT(vec.size() == ?, "Fill in the correct value."); + ASSERT(vec.size() == 5, "Fill in the correct value."); // THINK: `std::vector` 的大小是什么意思?与什么有关? - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + // // 在 64 位系统上,sizeof(vector) 通常是 24 (3个指针) + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); int ans[]{1, 2, 3, 4, 5}; - ASSERT(std::memcmp(vec.?, ans, sizeof(ans)) == 0, "Fill in the correct values."); + ASSERT(std::memcmp(vec.data(), ans, sizeof(ans)) == 0, "Fill in the correct values."); } { std::vector vec{1, 2, 3, 4, 5}; { - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(vec.size() == 5, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); double ans[]{1, 2, 3, 4, 5}; - ASSERT(std::memcmp(vec.?, ans, sizeof(ans)) == 0, "Fill in the correct values."); + ASSERT(std::memcmp(vec.data(), ans, sizeof(ans)) == 0, "Fill in the correct values."); } { - vec.push_back(6); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); - vec.pop_back(); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + vec.push_back(6);// 入栈 + ASSERT(vec.size() == 6, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); + vec.pop_back();// 出栈 + ASSERT(vec.size() == 5, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); } { vec[4] = 6; - ASSERT(vec[0] == ?, "Fill in the correct value."); - ASSERT(vec[1] == ?, "Fill in the correct value."); - ASSERT(vec[2] == ?, "Fill in the correct value."); - ASSERT(vec[3] == ?, "Fill in the correct value."); - ASSERT(vec[4] == ?, "Fill in the correct value."); + ASSERT(vec[0] == 1, "Fill in the correct value."); + ASSERT(vec[1] == 2, "Fill in the correct value."); + ASSERT(vec[2] == 3, "Fill in the correct value."); + ASSERT(vec[3] == 4, "Fill in the correct value."); + ASSERT(vec[4] == 6, "Fill in the correct value."); } { // THINK: `std::vector` 插入删除的时间复杂度是什么? - vec.insert(?, 1.5); + // insert 插入,在中间或头部插入会导致插入点之后的元素全部向后移动,时间复杂度为 $O(n)$。 + // - insert 的第一个参数必须是“迭代器”(Iterator),不能是下标。 + // - 插入单个元素 vec.insert(it+index, element)。; + // - 插入多个相同的元素 vec.insert(it+index, count, element)。; + + // auto it=vec.begin(); + // vec.insert(it+1, 1.5); + vec.insert(vec.begin() + 1, 1.5); ASSERT((vec == std::vector{1, 1.5, 2, 3, 4, 6}), "Make this assertion pass."); - vec.erase(?); + vec.erase(vec.begin() + 3); ASSERT((vec == std::vector{1, 1.5, 2, 4, 6}), "Make this assertion pass."); } { vec.shrink_to_fit(); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); + ASSERT(vec.capacity() == 5, "Fill in the correct value."); vec.clear(); - ASSERT(vec.empty(), "`vec` is empty now."); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); + ASSERT(vec.empty(), "`vec` is empty now.");// empty不改变capacity + ASSERT(vec.size() == 0, "Fill in the correct value."); + ASSERT(vec.capacity() == 5, "Fill in the correct value."); } } { - std::vector vec(?, ?); // TODO: 调用正确的构造函数 + std::vector vec(48, 'z'); // TODO: 调用正确的构造函数 ASSERT(vec[0] == 'z', "Make this assertion pass."); ASSERT(vec[47] == 'z', "Make this assertion pass."); ASSERT(vec.size() == 48, "Make this assertion pass."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); { - auto capacity = vec.capacity(); + // resize改变大小(size)和容量(capacity) vec.resize(16); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in a correct identifier."); + ASSERT(vec.size() == 16, "Fill in the correct value."); + ASSERT(vec.capacity() == 48, "Fill in a correct identifier."); } { + //reserve预留空间,只改变capacity vec.reserve(256); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); + ASSERT(vec.size() == 16, "Fill in the correct value."); + ASSERT(vec.capacity() == 256, "Fill in the correct value."); } { vec.push_back('a'); vec.push_back('b'); vec.push_back('c'); vec.push_back('d'); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); - ASSERT(vec[15] == ?, "Fill in the correct value."); - ASSERT(vec[?] == 'a', "Fill in the correct value."); - ASSERT(vec[?] == 'b', "Fill in the correct value."); - ASSERT(vec[?] == 'c', "Fill in the correct value."); - ASSERT(vec[?] == 'd', "Fill in the correct value."); + ASSERT(vec.size() == 20, "Fill in the correct value."); + ASSERT(vec.capacity() == 256, "Fill in the correct value."); + ASSERT(vec[15] == 'z', "Fill in the correct value."); + ASSERT(vec[16] == 'a', "Fill in the correct value."); + ASSERT(vec[17] == 'b', "Fill in the correct value."); + ASSERT(vec[18] == 'c', "Fill in the correct value."); + ASSERT(vec[19] == 'd', "Fill in the correct value."); } } diff --git a/exercises/26_std_vector_bool/main.cpp b/exercises/26_std_vector_bool/main.cpp index b4ab4f9c4..15103c20e 100644 --- a/exercises/26_std_vector_bool/main.cpp +++ b/exercises/26_std_vector_bool/main.cpp @@ -6,29 +6,29 @@ // TODO: 将下列 `?` 替换为正确的代码 int main(int argc, char **argv) { - std::vector vec(?, ?);// TODO: 正确调用构造函数 + std::vector vec(100, true);// TODO: 正确调用构造函数 ASSERT(vec[0], "Make this assertion pass."); ASSERT(vec[99], "Make this assertion pass."); ASSERT(vec.size() == 100, "Make this assertion pass."); // NOTICE: 平台相关!注意 CI:Ubuntu 上的值。 std::cout << "sizeof(std::vector) = " << sizeof(std::vector) << std::endl; - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(sizeof(vec) == 40, "Fill in the correct value."); { vec[20] = false; - ASSERT(?vec[20], "Fill in `vec[20]` or `!vec[20]`."); + ASSERT(!vec[20], "Fill in `vec[20]` or `!vec[20]`."); } { vec.push_back(false); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(?vec[100], "Fill in `vec[100]` or `!vec[100]`."); + ASSERT(vec.size() == 101, "Fill in the correct value."); + ASSERT(!vec[100], "Fill in `vec[100]` or `!vec[100]`."); } { auto ref = vec[30]; - ASSERT(?ref, "Fill in `ref` or `!ref`"); + ASSERT(ref, "Fill in `ref` or `!ref`"); ref = false; - ASSERT(?ref, "Fill in `ref` or `!ref`"); + ASSERT(!ref, "Fill in `ref` or `!ref`"); // THINK: WHAT and WHY? - ASSERT(?vec[30], "Fill in `vec[30]` or `!vec[30]`."); + ASSERT(!vec[30], "Fill in `vec[30]` or `!vec[30]`."); } return 0; } diff --git a/exercises/27_strides/main.cpp b/exercises/27_strides/main.cpp index baceaf2a9..e190d4a1d 100644 --- a/exercises/27_strides/main.cpp +++ b/exercises/27_strides/main.cpp @@ -18,6 +18,16 @@ std::vector strides(std::vector const &shape) { // TODO: 完成函数体,根据张量形状计算张量连续存储时的步长。 // READ: 逆向迭代器 std::vector::rbegin // 使用逆向迭代器可能可以简化代码 + + // 这里的逻辑是:从最后一个维度开始向前遍历。 + // 最后一个维度的步长总是 1(对于连续存储)。 + // 前一个维度的步长 = 后一个维度的步长 * 后一个维度的形状大小。 + udim current_stride = 1; + for(size_t i = shape.size(); i > 0; --i){ + // i-1为当前维度索引 + strides[i - 1] = current_stride; + current_stride *= shape[i - 1]; + } return strides; } diff --git a/exercises/28_std_string/main.cpp b/exercises/28_std_string/main.cpp index d8b276274..cf9175d2b 100644 --- a/exercises/28_std_string/main.cpp +++ b/exercises/28_std_string/main.cpp @@ -9,10 +9,18 @@ int main(int argc, char **argv) { auto hello = "Hello"s; auto world = "world"; // READ: `decltype` 表达式 + // `decltype`意为 "declare type"(声明类型) + // - 在编译期推导一个表达式或变量的类型,但不会实际计算表达式的值。 + // - int a = 10; + // - decltype(a) b = 20; // b 的类型是 int,因为 a 是 int + // - auto add(int x, double y) -> decltype(x + y); // 推导出返回类型为 double + // READ: `std::is_same_v` 元编程判别 - ASSERT((std::is_same_v), "Fill in the missing type."); - ASSERT((std::is_same_v), "Fill in the missing type."); + // std::is_same_v 是 C++17 引入的一个模板常量(属于 头文件)。 + // - 用于在编译期判断两个类型是否完全相同。 + ASSERT((std::is_same_v), "Fill in the missing type."); + ASSERT((std::is_same_v), "Fill in the missing type."); // TODO: 将 `?` 替换为正确的字符串 - ASSERT(hello + ", " + world + '!' == "?", "Fill in the missing string."); + ASSERT(hello + ", " + world + '!' == "Hello, world!", "Fill in the missing string."); return 0; } diff --git a/exercises/29_std_map/main.cpp b/exercises/29_std_map/main.cpp index fcccca347..68122a5fc 100644 --- a/exercises/29_std_map/main.cpp +++ b/exercises/29_std_map/main.cpp @@ -7,11 +7,13 @@ template bool key_exists(std::map const &map, k const &key) { // TODO: 实现函数 + return map.find(key) != map.end(); } template void set(std::map &map, k key, v value) { // TODO: 实现函数 + map[key] = value; } // ---- 不要修改以下代码 ---- diff --git a/exercises/30_std_unique_ptr/main.cpp b/exercises/30_std_unique_ptr/main.cpp index 9b98b5794..26feeef96 100644 --- a/exercises/30_std_unique_ptr/main.cpp +++ b/exercises/30_std_unique_ptr/main.cpp @@ -53,8 +53,8 @@ int main(int argc, char **argv) { {"fd"}, // TODO: 分析 problems[1] 中资源的生命周期,将记录填入 `std::vector` // NOTICE: 此题结果依赖对象析构逻辑,平台相关,提交时以 CI 实际运行平台为准 - {"", "", "", "", "", "", "", ""}, - {"", "", "", "", "", "", "", ""}, + {"d", "ffr"}, + {"d", "d","r"}, }; // ---- 不要修改以下代码 ---- diff --git a/exercises/31_std_shared_ptr/main.cpp b/exercises/31_std_shared_ptr/main.cpp index febbbcc6f..d35134457 100644 --- a/exercises/31_std_shared_ptr/main.cpp +++ b/exercises/31_std_shared_ptr/main.cpp @@ -10,36 +10,36 @@ int main(int argc, char **argv) { std::shared_ptr ptrs[]{shared, shared, shared}; std::weak_ptr observer = shared; - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 4, ""); ptrs[0].reset(); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 3, ""); ptrs[1] = nullptr; - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 2, ""); ptrs[2] = std::make_shared(*shared); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 1, ""); ptrs[0] = shared; ptrs[1] = shared; ptrs[2] = std::move(shared); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 3, ""); std::ignore = std::move(ptrs[0]); ptrs[1] = std::move(ptrs[1]); ptrs[1] = std::move(ptrs[2]); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 2, ""); shared = observer.lock(); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 3, ""); shared = nullptr; for (auto &ptr : ptrs) ptr = nullptr; - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 0, ""); shared = observer.lock(); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 0, ""); return 0; } diff --git a/exercises/32_std_transform/main.cpp b/exercises/32_std_transform/main.cpp index f4dc25a5c..948953bc0 100644 --- a/exercises/32_std_transform/main.cpp +++ b/exercises/32_std_transform/main.cpp @@ -10,6 +10,10 @@ int main(int argc, char **argv) { std::vector val{8, 13, 21, 34, 55}; // TODO: 调用 `std::transform`,将 `v` 中的每个元素乘以 2,并转换为字符串,存入 `ans` // std::vector ans + std::vector ans(val.size()); + std::transform(val.begin(), val.end(), ans.begin(), [](int x) { + return std::to_string(x * 2); + }); ASSERT(ans.size() == val.size(), "ans size should be equal to val size"); ASSERT(ans[0] == "16", "ans[0] should be 16"); ASSERT(ans[1] == "26", "ans[1] should be 26"); diff --git a/exercises/33_std_accumulate/main.cpp b/exercises/33_std_accumulate/main.cpp index 6326929d5..caeeccd3c 100644 --- a/exercises/33_std_accumulate/main.cpp +++ b/exercises/33_std_accumulate/main.cpp @@ -12,6 +12,7 @@ int main(int argc, char **argv) { // - 连续存储; // 的张量占用的字节数 // int size = + int size = std::accumulate(std::begin(shape), std::end(shape), sizeof(DataType), std::multiplies()); ASSERT(size == 602112, "4x1x3x224x224 = 602112"); return 0; }