From 0d463ec0e74c5bf3255f3056c144dc8a3ef3ef2c Mon Sep 17 00:00:00 2001 From: maohy0 Date: Tue, 20 Jan 2026 22:38:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90C++=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A34=E4=B8=AAexercises?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- exercises/00_hello_world/main.cpp | 2 +- exercises/01_variable&add/main.cpp | 1 + exercises/02_function/main.cpp | 2 + exercises/03_argument¶meter/main.cpp | 8 +-- exercises/04_static/main.cpp | 12 ++-- exercises/05_constexpr/main.cpp | 4 +- exercises/06_array/main.cpp | 4 +- exercises/07_loop/main.cpp | 4 +- exercises/08_pointer/main.cpp | 12 +++- exercises/09_enum&union/main.cpp | 1 + exercises/10_trivial/main.cpp | 6 +- exercises/11_method/main.cpp | 4 +- exercises/12_method_const/main.cpp | 3 +- exercises/13_class/main.cpp | 4 +- exercises/14_class_destruct/main.cpp | 8 ++- exercises/15_class_clone/main.cpp | 14 ++-- exercises/16_class_move/main.cpp | 23 +++++-- exercises/17_class_derive/main.cpp | 6 +- exercises/18_class_virtual/main.cpp | 43 ++++++------ exercises/19_class_virtual_destruct/main.cpp | 25 +++---- exercises/20_function_template/main.cpp | 5 +- exercises/21_runtime_datatype/main.cpp | 8 ++- exercises/22_class_template/main.cpp | 18 ++++- exercises/23_template_const/main.cpp | 6 ++ exercises/24_std_array/main.cpp | 16 ++--- exercises/25_std_vector/main.cpp | 70 ++++++++++---------- exercises/26_std_vector_bool/main.cpp | 18 ++--- exercises/27_strides/main.cpp | 6 ++ exercises/28_std_string/main.cpp | 8 ++- exercises/29_std_map/main.cpp | 3 + exercises/30_std_unique_ptr/main.cpp | 29 ++++++-- exercises/31_std_shared_ptr/main.cpp | 34 ++++++---- exercises/32_std_transform/main.cpp | 17 ++++- exercises/33_std_accumulate/main.cpp | 8 ++- exercises/xmake.lua | 2 + xmake.lua | 2 + 36 files changed, 285 insertions(+), 151 deletions(-) diff --git a/exercises/00_hello_world/main.cpp b/exercises/00_hello_world/main.cpp index 8866f3c15..fa454e132 100644 --- a/exercises/00_hello_world/main.cpp +++ b/exercises/00_hello_world/main.cpp @@ -6,6 +6,6 @@ int main(int argc, char **argv) { // TODO: 在控制台输出 "Hello, InfiniTensor!" 并换行 - std::cout : "Hello, InfiniTensor!" + std::endl; + std::cout << "Hello, InfiniTensor!" << std::endl; return 0; } diff --git a/exercises/01_variable&add/main.cpp b/exercises/01_variable&add/main.cpp index 5014863fd..71fabf2b4 100644 --- a/exercises/01_variable&add/main.cpp +++ b/exercises/01_variable&add/main.cpp @@ -5,6 +5,7 @@ int main(int argc, char **argv) { // TODO: 补全变量定义并打印加法运算 // x ? + int x = 1; std::cout << x << " + " << x << " = " << x + x << std::endl; return 0; } diff --git a/exercises/02_function/main.cpp b/exercises/02_function/main.cpp index b5eef7f28..be4dcefa3 100644 --- a/exercises/02_function/main.cpp +++ b/exercises/02_function/main.cpp @@ -5,6 +5,7 @@ // NOTICE: 补充由内而外读法的机翻解释 // TODO: 在这里声明函数 +int add(int a, int b); int main(int argc, char **argv) { ASSERT(add(123, 456) == 123 + 456, "add(123, 456) should be 123 + 456"); @@ -16,4 +17,5 @@ int main(int argc, char **argv) { int add(int a, int b) { // TODO: 补全函数定义,但不要移动代码行 + return a + b; } diff --git a/exercises/03_argument¶meter/main.cpp b/exercises/03_argument¶meter/main.cpp index 7fb5d3c2f..76136eae6 100644 --- a/exercises/03_argument¶meter/main.cpp +++ b/exercises/03_argument¶meter/main.cpp @@ -8,19 +8,19 @@ void func(int); // TODO: 为下列 ASSERT 填写正确的值 int main(int argc, char **argv) { auto arg = 99; - ASSERT(arg == ?, "arg should be ?"); + ASSERT(arg == 99, "arg should be ?"); std::cout << "befor func call: " << arg << std::endl; func(arg); - ASSERT(arg == ?, "arg should be ?"); + ASSERT(arg == 99, "arg should be ?"); std::cout << "after func call: " << arg << std::endl; return 0; } // TODO: 为下列 ASSERT 填写正确的值 void func(int param) { - ASSERT(param == ?, "param should be ?"); + ASSERT(param == 99, "param should be ?"); std::cout << "befor add: " << param << std::endl; param += 1; - ASSERT(param == ?, "param should be ?"); + ASSERT(param == 100, "param should be ?"); std::cout << "after add: " << param << std::endl; } diff --git a/exercises/04_static/main.cpp b/exercises/04_static/main.cpp index f107762fa..88f05a505 100644 --- a/exercises/04_static/main.cpp +++ b/exercises/04_static/main.cpp @@ -2,6 +2,8 @@ // READ: `static` 关键字 // THINK: 这个函数的两个 `static` 各自的作用是什么? +// 函数的static表示这个func只可以在本源文件中使用,其他文件不能用extern链接到 +// static_的static表示这个变量在整个生命周期内存在,函数调用结束后不会销毁,所以static_只有1次初始化 static int func(int param) { static int static_ = param; // std::cout << "static_ = " << static_ << std::endl; @@ -10,10 +12,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..c256ab0fc 100644 --- a/exercises/05_constexpr/main.cpp +++ b/exercises/05_constexpr/main.cpp @@ -1,5 +1,7 @@ #include "../exercise.h" +// const 是运行时常量,保证对象创建后不被修改;constexpr 是编译期常量,强制值必须在编译阶段就能确定 + constexpr unsigned long long fibonacci(int i) { switch (i) { case 0: @@ -18,7 +20,7 @@ int main(int argc, char **argv) { // TODO: 观察错误信息,修改一处,使代码编译运行 // PS: 编译运行,但是不一定能算出结果…… - constexpr auto ANS_N = 90; + constexpr auto ANS_N = 30; // constexpr 函数虽然能在编译期计算,但编译器对递归深度和计算复杂度有实际限制。fibonacci(90) 的递归调用呈指数级增长(约 2^90 次调用),远超编译器能处理的编译期计算极限, 修改为30可以解决问题 constexpr auto ANS = fibonacci(ANS_N); std::cout << "fibonacci(" << ANS_N << ") = " << ANS << std::endl; diff --git a/exercises/06_array/main.cpp b/exercises/06_array/main.cpp index 61ed99ec0..4c35e34d4 100644 --- a/exercises/06_array/main.cpp +++ b/exercises/06_array/main.cpp @@ -11,13 +11,13 @@ 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"); + ASSERT(sizeof(arr) == 90*8, "sizeof array is size of all its elements"); // unsigned long long一个元素占8个字节 // ---- 不要修改以下代码 ---- ASSERT(fibonacci(2) == 1, "fibonacci(2) should be 1"); ASSERT(fibonacci(20) == 6765, "fibonacci(20) should be 6765"); diff --git a/exercises/07_loop/main.cpp b/exercises/07_loop/main.cpp index 44fd835cd..66eadaf8e 100644 --- a/exercises/07_loop/main.cpp +++ b/exercises/07_loop/main.cpp @@ -5,9 +5,9 @@ // READ: 纯函数 static unsigned long long fibonacci(int i) { // TODO: 为缓存设置正确的初始值 - static unsigned long long cache[96], cached; + static unsigned long long cache[96]{0, 1}, cached; // TODO: 设置正确的循环条件 - for (; false; ++cached) { + for (cached = 2; cached <= i && i >= 2; ++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..de0762e51 100644 --- a/exercises/08_pointer/main.cpp +++ b/exercises/08_pointer/main.cpp @@ -3,8 +3,16 @@ // READ: 数组向指针退化 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] + // TODO: 编写代码判断从 ptr 开始,每 stride 个元素取 1 个元素,组成长度为 n 的数列是否满足 arr[i + 2] = arr[i] + arr[i + 1] + for(int i = 0; i < len - 2; ++i) { + int idx1 = i * stride; + int idx2 = idx1 + stride; + int idx3 = idx2 + stride; + + if(*(ptr + idx3) != *(ptr + idx1) + *(ptr + idx2)) { + return false; + } + } return true; } diff --git a/exercises/09_enum&union/main.cpp b/exercises/09_enum&union/main.cpp index 3f2cec768..49e5bdfbb 100644 --- a/exercises/09_enum&union/main.cpp +++ b/exercises/09_enum&union/main.cpp @@ -37,6 +37,7 @@ ColorEnum convert_by_pun(Color c) { TypePun pun; // TODO: 补全类型双关转换 + pun.c = c; // 将Color类型的值存入联合体,从同一内存位置以ColorEnum读取 return pun.e; } diff --git a/exercises/10_trivial/main.cpp b/exercises/10_trivial/main.cpp index 6ba23e48e..4785602bd 100644 --- a/exercises/10_trivial/main.cpp +++ b/exercises/10_trivial/main.cpp @@ -9,8 +9,8 @@ struct FibonacciCache { // TODO: 实现正确的缓存优化斐波那契计算 static unsigned long long fibonacci(FibonacciCache &cache, int i) { - for (; false; ++cached) { - cache[cached] = cache[cached - 1] + cache[cached - 2]; + for (cache.cached = 2; cache.cached <= i; ++cache.cached) { + cache.cache[cache.cached] = cache.cache[cache.cached - 1] + cache.cache[cache.cached - 2]; } return cache.cache[i]; } @@ -19,7 +19,7 @@ int main(int argc, char **argv) { // TODO: 初始化缓存结构体,使计算正确 // NOTICE: C/C++ 中,读取未初始化的变量(包括结构体变量)是未定义行为 // READ: 初始化的各种写法 - FibonacciCache fib; + FibonacciCache fib{.cache={0, 1}}; 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..81bbb3e20 100644 --- a/exercises/11_method/main.cpp +++ b/exercises/11_method/main.cpp @@ -6,7 +6,7 @@ struct Fibonacci { // TODO: 实现正确的缓存优化斐波那契计算 unsigned long long get(int i) { - for (; false; ++cached) { + for (cached = 2; cached <= i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; @@ -15,7 +15,7 @@ struct Fibonacci { int main(int argc, char **argv) { // TODO: 初始化缓存结构体,使计算正确 - Fibonacci fib; + Fibonacci fib{.cache={0, 1}}; 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..65c079be1 100644 --- a/exercises/12_method_const/main.cpp +++ b/exercises/12_method_const/main.cpp @@ -5,7 +5,8 @@ struct Fibonacci { int numbers[11]; // TODO: 修改方法签名和实现,使测试通过 - int get(int i) { + int get(int i) const { + return numbers[i]; } }; diff --git a/exercises/13_class/main.cpp b/exercises/13_class/main.cpp index 9afa98c5b..b91251546 100644 --- a/exercises/13_class/main.cpp +++ b/exercises/13_class/main.cpp @@ -14,11 +14,11 @@ class Fibonacci { public: // TODO: 实现构造器 - // Fibonacci() + Fibonacci() : cache({0, 1}) {} // TODO: 实现正确的缓存优化斐波那契计算 size_t get(int i) { - for (; false; ++cached) { + for (cached = 2; cached <= i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; diff --git a/exercises/14_class_destruct/main.cpp b/exercises/14_class_destruct/main.cpp index 42150e8ca..644700384 100644 --- a/exercises/14_class_destruct/main.cpp +++ b/exercises/14_class_destruct/main.cpp @@ -11,14 +11,16 @@ class DynFibonacci { public: // TODO: 实现动态设置容量的构造器 - DynFibonacci(int capacity): cache(new ?), cached(?) {} + DynFibonacci(int capacity): cache(new size_t[capacity]{0, 1}), cached(2) {} // TODO: 实现析构器,释放缓存空间 - ~DynFibonacci(); + ~DynFibonacci() { + delete[] cache; + } // TODO: 实现正确的缓存优化斐波那契计算 size_t get(int i) { - for (; false; ++cached) { + for (; cached <= i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; diff --git a/exercises/15_class_clone/main.cpp b/exercises/15_class_clone/main.cpp index f74b70391..3b5d55b0e 100644 --- a/exercises/15_class_clone/main.cpp +++ b/exercises/15_class_clone/main.cpp @@ -10,17 +10,23 @@ class DynFibonacci { public: // TODO: 实现动态设置容量的构造器 - DynFibonacci(int capacity): cache(new ?), cached(?) {} + DynFibonacci(int capacity): cache(new size_t[capacity + 1]{0, 1}), cached(2) {} // TODO: 实现复制构造器 - DynFibonacci(DynFibonacci const &) = delete; + DynFibonacci(DynFibonacci const &other) : cache(new size_t[other.cached + 1]), cached(other.cached) { + for(int i = 0; i <= cached; ++i){ + cache[i] = other.cache[i]; + } + } // TODO: 实现析构器,释放缓存空间 - ~DynFibonacci(); + ~DynFibonacci() { + delete[] cache; + } // TODO: 实现正确的缓存优化斐波那契计算 size_t get(int i) { - for (; false; ++cached) { + for (; cached <= i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; diff --git a/exercises/16_class_move/main.cpp b/exercises/16_class_move/main.cpp index 8d2c421da..fab8f22b1 100644 --- a/exercises/16_class_move/main.cpp +++ b/exercises/16_class_move/main.cpp @@ -15,21 +15,34 @@ class DynFibonacci { public: // TODO: 实现动态设置容量的构造器 - DynFibonacci(int capacity): cache(new ?), cached(?) {} + DynFibonacci(int capacity): cache(new size_t[capacity + 1]{0, 1}), cached(2) {} // TODO: 实现移动构造器 - DynFibonacci(DynFibonacci &&) noexcept = delete; + DynFibonacci(DynFibonacci &&other) : cache{new size_t[other.cached + 1]}, cached{other.cached} { + for(int i = 0; i <= cached; ++i) { + cache[i] = other.cache[i]; + } + other.cache = nullptr; + } // TODO: 实现移动赋值 // NOTICE: ⚠ 注意移动到自身问题 ⚠ - DynFibonacci &operator=(DynFibonacci &&) noexcept = delete; + DynFibonacci &operator=(DynFibonacci &&other) { + if(this != &other) { + delete[] cache; + cached = other.cached; + cache = new size_t[cached + 1]; + for(int i = 0; i <= cached; ++i) cache[i] = other.cache[i]; + } + 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..0c245df4f 100644 --- a/exercises/17_class_derive/main.cpp +++ b/exercises/17_class_derive/main.cpp @@ -50,9 +50,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..dadf9313c 100644 --- a/exercises/18_class_virtual/main.cpp +++ b/exercises/18_class_virtual/main.cpp @@ -1,6 +1,7 @@ #include "../exercise.h" // READ: 虚函数 +// 虚函数是实现运行时多态的核心机制,它允许通过基类指针/引用调用派生类的函数实现 struct A { virtual char virtual_name() const { @@ -42,38 +43,40 @@ 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..999098501 100644 --- a/exercises/19_class_virtual_destruct/main.cpp +++ b/exercises/19_class_virtual_destruct/main.cpp @@ -5,12 +5,13 @@ struct A { // TODO: 正确初始化静态字段 - static int num_a = 0; + static inline int num_a = 0; A() { ++num_a; } - ~A() { + // 通过基类指针删除派生类对象的时候,如果基类析构函数不是虚的,会导致派生类部分不被析构,造成内存泄漏 + virtual ~A() { --num_a; } @@ -20,7 +21,7 @@ struct A { }; struct B final : public A { // TODO: 正确初始化静态字段 - static int num_b = 0; + static inline int num_b = 0; B() { ++num_b; @@ -37,10 +38,10 @@ 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()"); + 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 +49,13 @@ 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()"); + B &bb = *(B*)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..07421a84a 100644 --- a/exercises/20_function_template/main.cpp +++ b/exercises/20_function_template/main.cpp @@ -2,7 +2,8 @@ // READ: 函数模板 // TODO: 将这个函数模板化 -int plus(int a, int b) { +template +T plus(T a, T b) { return a + b; } @@ -14,7 +15,7 @@ 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(plus(0.1f, 0.2f) == 0.3f, "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..4cdd4f54e 100644 --- a/exercises/21_runtime_datatype/main.cpp +++ b/exercises/21_runtime_datatype/main.cpp @@ -18,13 +18,19 @@ struct TaggedUnion { }; // TODO: 将这个函数模板化用于 sigmoid_dyn -float sigmoid(float x) { +template +T sigmoid(T x) { return 1 / (1 + std::exp(-x)); } TaggedUnion sigmoid_dyn(TaggedUnion x) { TaggedUnion ans{x.type}; // TODO: 根据 type 调用 sigmoid + if(ans.type == DataType::Float) { + ans.f = sigmoid(x.f); + } else if(ans.type == DataType::Double) { + ans.d = sigmoid(x.d); + } return ans; } diff --git a/exercises/22_class_template/main.cpp b/exercises/22_class_template/main.cpp index d4985d904..909a89652 100644 --- a/exercises/22_class_template/main.cpp +++ b/exercises/22_class_template/main.cpp @@ -8,8 +8,9 @@ struct Tensor4D { T *data; Tensor4D(unsigned int const shape_[4], T const *data_) { - unsigned int size = 1; + unsigned int size = shape_[0] * shape_[1] * shape_[2] * shape_[3]; // TODO: 填入正确的 shape 并计算 size + shape[0] = shape_[0], shape[1] = shape_[1], shape[2] = shape_[2], shape[3] = shape_[3]; data = new T[size]; std::memcpy(data, data_, size * sizeof(T)); } @@ -28,6 +29,21 @@ struct Tensor4D { // 则 `this` 与 `others` 相加时,3 个形状为 `[1, 2, 1, 4]` 的子张量各自与 `others` 对应项相加。 Tensor4D &operator+=(Tensor4D const &others) { // TODO: 实现单向广播的加法 + for(int i = 0; i < shape[0]; ++i) { + for(int j = 0; j < shape[1]; ++j) { + for(int k = 0; k < shape[2]; ++k) { + for(int l = 0; l < shape[3]; ++l) { + // 形状不同的维度只能是1,所以不算很复杂,把o*赋值0就是可以用多次,维度一样就对应着计算 + int oi = others.shape[0] == 1 ? 0 : i; + int oj = others.shape[1] == 1 ? 0 : j; + int ok = others.shape[2] == 1 ? 0 : k; + int ol = others.shape[3] == 1 ? 0 : l; + + data[l + i * shape[1] * shape[2] * shape[3] + j * shape[2] * shape[3] + k * shape[3]] += others.data[ol + oi * others.shape[1] * others.shape[2] * others.shape[3] + oj * others.shape[2] * others.shape[3] + ok * others.shape[3]]; + } + } + } + } return *this; } }; diff --git a/exercises/23_template_const/main.cpp b/exercises/23_template_const/main.cpp index e0105e168..b294123a3 100644 --- a/exercises/23_template_const/main.cpp +++ b/exercises/23_template_const/main.cpp @@ -10,7 +10,12 @@ struct Tensor { Tensor(unsigned int const shape_[N]) { unsigned int size = 1; + // 这个要拷贝给shape,后面要用shape而不是shape_ + std::memcpy(shape, shape_, N * sizeof(unsigned int)); // TODO: 填入正确的 shape 并计算 size + for(unsigned int i = 0; i < N; ++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..8d93f156b 100644 --- a/exercises/24_std_array/main.cpp +++ b/exercises/24_std_array/main.cpp @@ -8,21 +8,21 @@ 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) == 4 * 5, "Fill in the correct value."); int ans[]{1, 2, 3, 4, 5}; - ASSERT(std::memcmp(arr.?, ans, ?) == 0, "Fill in the correct values."); + ASSERT(std::memcmp(arr.data(), ans, 5) == 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) == 8 * 8, "Fill in the correct value."); } { 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."); + 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..ccc0410bb 100644 --- a/exercises/25_std_vector/main.cpp +++ b/exercises/25_std_vector/main.cpp @@ -8,81 +8,83 @@ 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."); + // sizeof(vec)是vector对象本身的大小,不是元素总大小,在64位系统就是24,3个指针 + // 另外,vec.size()是vector中元素的数量,vec.capacity()是底层分配的数组数量,vec.data()是指向实际数组的指针 + 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."); + ASSERT(vec.size() == 6, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); vec.pop_back(); - 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."); } { 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); + 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."); + vec.shrink_to_fit(); // 请求缩小容量到至少size(),会改变capacity() + 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.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(); 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() == capacity, "Fill in a correct identifier."); } { 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..632c57778 100644 --- a/exercises/26_std_vector_bool/main.cpp +++ b/exercises/26_std_vector_bool/main.cpp @@ -3,32 +3,34 @@ // READ: std::vector // READ: 模板特化 +// std::vector就是一个特化版本,跟普通的std::vector不同 // 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]`."); + // 因为ref在这里是std::vector::reference (由auto推导的), 修改会反映到原数据,类似引用 + 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..1e85d2a8b 100644 --- a/exercises/27_strides/main.cpp +++ b/exercises/27_strides/main.cpp @@ -18,6 +18,12 @@ std::vector strides(std::vector const &shape) { // TODO: 完成函数体,根据张量形状计算张量连续存储时的步长。 // READ: 逆向迭代器 std::vector::rbegin // 使用逆向迭代器可能可以简化代码 + strides[shape.size() - 1] = 1; + std::vector::const_reverse_iterator shape_i = shape.crbegin() + 1; // 只读元素 + std::vector::reverse_iterator strides_i = strides.rbegin() + 1; + for(; shape_i != shape.crend() && strides_i != strides.rend(); ++shape_i, ++strides_i) { + *strides_i = *(shape_i - 1) * *(strides_i - 1); + } return strides; } diff --git a/exercises/28_std_string/main.cpp b/exercises/28_std_string/main.cpp index d8b276274..5eb08145b 100644 --- a/exercises/28_std_string/main.cpp +++ b/exercises/28_std_string/main.cpp @@ -10,9 +10,11 @@ int main(int argc, char **argv) { auto world = "world"; // READ: `decltype` 表达式 // 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."); + // decltype也是推导数据类型的,可以对任意表达式,并且不对表达式求值 + // is_same_v顾名思义,是个类型比较工具,在编译期看两个类型是否一样 + 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..5013d88ec 100644 --- a/exercises/29_std_map/main.cpp +++ b/exercises/29_std_map/main.cpp @@ -7,11 +7,14 @@ template bool key_exists(std::map const &map, k const &key) { // TODO: 实现函数 + // 只要没找到最后都没有,就是key存在于map中 + 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..3c234240b 100644 --- a/exercises/30_std_unique_ptr/main.cpp +++ b/exercises/30_std_unique_ptr/main.cpp @@ -5,6 +5,10 @@ #include // READ: `std::unique_ptr` +// unique_ptr在同一时间只有一个unique_ptr指向对象,换句话说,一个对象只能被1个unique_ptr拥有 +// 只能移动,不能拷贝,移动不会释放对象,是所有权转移 +// unique_ptr释放对象的情况:被另一个unique_ptr赋值、被置为nullptr、离开作用域时自动释放资源 +// 释放对象指的是,销毁指向的对象(调用析构函数)、释放内存、然后unique_ptr变为nullptr std::vector RECORDS; @@ -17,7 +21,7 @@ class Resource { } ~Resource() { - RECORDS.push_back(_records); + RECORDS.push_back(_records); // 析构的时候记录所有操作 } }; @@ -52,9 +56,26 @@ int main(int argc, char **argv) { std::vector answers[]{ {"fd"}, // TODO: 分析 problems[1] 中资源的生命周期,将记录填入 `std::vector` + // problems[1]产生2个资源,分别记为res1和res2,首先reset(nullptr), 传入nullptr不记录,创建res1 + // 然后forward(res1), 记录f,保持返回res1 + // forward(res1), 记录f, 保持返回res1 + // reset(res1), 非nullptr, 记录r, **应该调用析构函数**,把ffr推入RECORDS, 创建res2 + // drop(res2), 记录d,把d推入RECORDS,形参ptr离开作用域,res2**应该析构**, 返回nullptr + // forward(nullptr),无事发生 + // NOTICE: 此题结果依赖对象析构逻辑,平台相关,提交时以 CI 实际运行平台为准 - {"", "", "", "", "", "", "", ""}, - {"", "", "", "", "", "", "", ""}, + // 再细说的话就是在该编译环境下,最外层生成的对象先于内层的对象析构,所以这里要和推导顺序反着写,可能在有些编译环境下是正着写 + // 现在采用的是Windows+Xmake+MinGW, 编译器可能是临时对象在完整表达式结束后(就是一整行代码结束后)才开始销毁对象,清理顺序后进先出可以理解为栈的pop,后产生的对象先清理,先析构 + // 有些编译器可能是函数执行完后就析构对象,那样的是正向写的 + {"d", "ffr"}, + {"d", "d", "r"}, + // 对于problem[2]也是类似的,分别记为r1, r2和r3 + // 先reset(nullptr), 传入nullptr不记录,创建r1 + // 然后reset(r1), 记录r, r1死亡,**应该调用析构函数**,把r推入RECORDS,创建r2 + // drop(r2), 记录d,返回nullptr,r2死亡,调用析构函数把d推入RECORDS + // reset(nullptr), 传入nullptr,创建r3 + // drop(r3), 记录d, 返回nullptr,r3死亡,调用析构函数把d推入RECORDS + // drop(nullptr), 无事发生 }; // ---- 不要修改以下代码 ---- @@ -67,4 +88,4 @@ int main(int argc, char **argv) { } return 0; -} +} \ No newline at end of file diff --git a/exercises/31_std_shared_ptr/main.cpp b/exercises/31_std_shared_ptr/main.cpp index febbbcc6f..34620f2b7 100644 --- a/exercises/31_std_shared_ptr/main.cpp +++ b/exercises/31_std_shared_ptr/main.cpp @@ -4,42 +4,48 @@ // READ: `std::shared_ptr` // READ: `std::weak_ptr` +// std::shared_ptr 实现的是共享所有权,多个指针可以同时指向一个对象,创建一个shared_ptr时,系统会在堆上创建一个控制块,计数有多少个shared_ptr(强引用计数)和weak_ptr(弱引用计数)指向该对象 +// std::weak_ptr指向对象但不拥有对象,它的use_count返回的是指向该对象的shared_ptr数量 + // TODO: 将下列 `?` 替换为正确的值 int main(int argc, char **argv) { auto shared = std::make_shared(10); - std::shared_ptr ptrs[]{shared, shared, shared}; + std::shared_ptr ptrs[]{shared, shared, shared}; // 拷贝了3次 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() == ?, ""); + ptrs[2] = std::make_shared(*shared); // 这一步相当于创建了一个新的对象,让ptrs[2]指向新对象,2个对象虽然值一样,但是地址不一样,是2个东西 + ASSERT(observer.use_count() == 1, ""); ptrs[0] = shared; ptrs[1] = shared; - ptrs[2] = std::move(shared); - ASSERT(observer.use_count() == ?, ""); + ptrs[2] = std::move(shared); // 移动语义,把shared掏空,3个是ptrs[0], ptrs[1], ptrs[2] + ASSERT(observer.use_count() == 3, ""); - std::ignore = std::move(ptrs[0]); + std::ignore = std::move(ptrs[0]); // std::ignore一般用来占位并忽略掉不需要的值,但其实没有执行完一行代码自己销毁的机制,可以理解为只是叫这个名字,所以这里的observer.use_count()不要-1 + ASSERT(observer.use_count() == 3, ""); ptrs[1] = std::move(ptrs[1]); + ASSERT(observer.use_count() == 3, ""); ptrs[1] = std::move(ptrs[2]); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 2, ""); - shared = observer.lock(); - ASSERT(observer.use_count() == ?, ""); + shared = observer.lock(); // lock将weak_ptr提升为shared_ptr,shared像胡汉三一样又回来了,然后lock的函数签名里有const,不改变observer本身还是weak_ptr,所以计数要+1 + ASSERT(observer.use_count() == 3, ""); shared = nullptr; + // 这个for循环跟Python写法for ptr in ptrs一样的逻辑,Python的for循环也是引用,会改变源变量的值,C++要指定清楚是引用还是值传递 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..30e9e3219 100644 --- a/exercises/32_std_transform/main.cpp +++ b/exercises/32_std_transform/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include // READ: `std::transform` // READ: `std::vector::begin` @@ -9,7 +10,21 @@ 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(5); + // 前2个参数是输入范围,2个迭代器,第3个参数是输出位置,从这里开始存放数据 + // [](int x){...}是C++的匿名函数写法,[]表示函数内不能使用函数外的变量,[=]表示可以以值传递的方式拿所有外部变量,[&]是引用方式捕获所有外部变量,[x, &y]表示值捕获x,引用捕获y, [=, &y]表示默认值捕获,y是引用,(int x)就是传参 + // -> std::string表示返回值类型,可以不写,函数体跟命名函数一样,还有返回值 + // 用法举例还有,跟Python的lambda差不多 + // int factor = 2; + // auto multiply = [factor](int x) -> int{return x * factor}; + // std::cout << multiply(5) << std::endl; // 输出 10 + std::transform(val.begin(), val.end(), ans.begin(), [](int x) -> std::string{ + std::stringstream ss; + ss << x * 2; + std::string ret; + ss >> ret; + return ret; + }); 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..e602ef2b2 100644 --- a/exercises/33_std_accumulate/main.cpp +++ b/exercises/33_std_accumulate/main.cpp @@ -2,6 +2,9 @@ #include // READ: `std::accumulate` +// accumulate中文就是累积的意思,相对浅显的用法可以看https://blog.csdn.net/qq_40803710/article/details/80273811 +// 一般来说,accumulate就是求和,但提供第4个参数,也可以做一些二元运算, std::multiplies是乘法的二元函数对象 +// 前2个参数就是起止范围, 第3个参数是初始值 int main(int argc, char **argv) { using DataType = float; @@ -9,9 +12,8 @@ int main(int argc, char **argv) { // TODO: 调用 `std::accumulate` 计算: // - 数据类型为 float; // - 形状为 shape; - // - 连续存储; - // 的张量占用的字节数 - // int size = + // - 连续存储的张量占用的字节数,所以初始值不是1而是用4来乘 + int size = std::accumulate(shape, shape + sizeof(shape) / sizeof(shape[0]), sizeof(float), std::multiplies()); ASSERT(size == 602112, "4x1x3x224x224 = 602112"); return 0; } diff --git a/exercises/xmake.lua b/exercises/xmake.lua index 0c3b11bfd..bc1737d79 100644 --- a/exercises/xmake.lua +++ b/exercises/xmake.lua @@ -3,6 +3,8 @@ set_encodings("utf-8") set_warnings("all") set_kind("binary") set_languages("cxx17") +-- 添加编译toolchains,使用mingw/g++ +set_toolchains("mingw") -- 格式化输出 target("exercise00") diff --git a/xmake.lua b/xmake.lua index fa3263bd3..009b042a6 100644 --- a/xmake.lua +++ b/xmake.lua @@ -2,6 +2,8 @@ add_rules("mode.debug", "mode.release") set_encodings("utf-8") set_warnings("all") set_languages("cxx17") +-- 添加编译toolchains,使用mingw/g++ +set_toolchains("mingw") target("test") set_kind("static")