diff --git a/exercises/34_lambda/main.cpp b/exercises/34_lambda/main.cpp new file mode 100755 index 000000000..3b7f7801a --- /dev/null +++ b/exercises/34_lambda/main.cpp @@ -0,0 +1,75 @@ +#include "../exercise.h" +#include +#include + +// READ: `lambda` + +int main(int argc, char **argv) { + { + std::vector numbers{1, 2, 3, 4, 5}; + int sum = 0; + + std::for_each(numbers.begin(), numbers.end(), [&sum](int n) { + sum += n; + }); + + // TODO: 为下列 ASSERT 填写正确的值 + ASSERT(sum == ?, "Sum of numbers should be ?"); + + auto is_even = [](int n) { return n % 2 == 0; }; + std::vector evens; + std::copy_if(numbers.begin(), numbers.end(), std::back_inserter(evens), is_even); + + ASSERT(evens.size() == ?, "There should be ? even numbers"); + ASSERT(evens[0] == ? && evens[1] == ?, "Even numbers should be ?"); + + // TODO: 使用 Lambda 表达式计算奇数的平方和 + int odd_square_sum = 0; + std::for_each(numbers.begin(), numbers.end(), ?); + ASSERT(odd_square_sum == 35, "Sum of squares of odd numbers should be 35"); + } + { + // TODO: 为下面的 ? 填写正确的值 + auto create_adder = [](int x) { + return [x](int y) { return x + y; }; + }; + auto add_five = create_adder(?); + ASSERT(add_five(?) == 8, "5 + 3 should be 8"); + + // 创建一个乘法器的 Lambda 表达式 + // TODO: 返回一个 Lambda 表达式 + auto create_multiplier = ?; + auto multiply_by_three = create_multiplier(3); + ASSERT(multiply_by_three(4) == 12, "3 * 4 should be 12"); + } + { + // 使用 Lambda 表达式捕获外部变量 + // TODO: 为下面的 ? 填写正确的表达式 + int factor = 10; + auto multiply_by_factor = [?](int x) { + return x * factor; + }; + ASSERT(multiply_by_factor(2) == 20, "2 * 10 should be 20"); + } + { + // 递归 Lambda 表达式(计算阶乘) + std::function factorial; + // TODO: 替换下面的 ?,实现正确的 Lambda 表达式,计算阶乘 + factorial = [?](int n) { + ? + }; + + ASSERT(factorial(0) == 1, "Factorial of 0 should be 1"); + ASSERT(factorial(5) == 120, "5! should be 120"); + ASSERT(factorial(7) == 5040, "7! should be 5040"); + + // 递归 Lambda 表达式(fibonacci 数列) + // TODO: 替换下面的 ?,实现正确的 Lambda 表达式,计算 fibonacci 数列 + std::function fib; + fib = [?](int n) { + ? + }; + ASSERT(fib(7) == 13, "7th Fibonacci number should be 13"); + } + return 0; +} diff --git a/exercises/35_optional/main.cpp b/exercises/35_optional/main.cpp new file mode 100755 index 000000000..d9d3758fe --- /dev/null +++ b/exercises/35_optional/main.cpp @@ -0,0 +1,62 @@ +#include "../exercise.h" +#include +#include + +// READ: `optional` + +std::optional find_even(const std::vector &nums) { + for (int n : nums) { + if (n % 2 == 0) { + return n; + } + } + return std::nullopt; +} + +int main(int argc, char **argv) { + // TODO: 为下列 ASSERT 中填写正确的值 + { + std::vector nums{1, 3, 5, 7, 8}; + auto result = find_even(nums); + ASSERT(?, "填入 result.has_value() 或 !result.has_value()"); + ASSERT(result.value() == ?, "The even number should be ?"); + + std::vector odd_nums{1, 3, 5, 7}; + auto no_even = find_even(odd_nums); + // TODO: 为 ? 填写正确的值 + int default_value = no_even.value_or(?); + ASSERT(default_value == -1, "Default value should be -1 when no even number is found"); + } + { + std::optional opt_value; + ASSERT(?, "填入 opt_value.has_value() 或 !opt_value.has_value()"); + opt_value.emplace(42); + ASSERT(?, "填入 opt_value.has_value() 或 !opt_value.has_value()"); + ASSERT(opt_value.value() == ?, "The value should be ?"); + + std::optional empty_opt; + ASSERT(empty_opt ? std::nullopt, "填入 == 或 !="); + ASSERT(opt_value ? std::nullopt, "填入 == 或 !="); + + opt_value.reset(); + ASSERT(?, "填入 opt_value.has_value() 或 !opt_value.has_value()"); + ASSERT(opt_value ? std::nullopt, "填入 == 或 !=y"); + } + { + // 测试移动构造和赋值 + std::optional original("Hello World"); + std::optional moved = std::move(original); + original.reset(); + // TODO: 为 ? 填写正确的值 + ASSERT(original ? std::nullopt, "填入 == 或 !="); + ASSERT(?, "填入 moved.has_value() 或 !moved.has_value()"); + } + { + // 测试 make_optional + auto str_opt = std::make_optional(5, 'c'); + ASSERT(str_opt.has_value(), "make_optional should create value"); + // TODO: 为 ? 填写正确的值 + ASSERT(*str_opt == ?, "填入正确的字符串值"); + } + return 0; +} \ No newline at end of file diff --git a/exercises/36_variant/main.cpp b/exercises/36_variant/main.cpp new file mode 100755 index 000000000..4334381f3 --- /dev/null +++ b/exercises/36_variant/main.cpp @@ -0,0 +1,49 @@ +#include "../exercise.h" +#include +#include + +// READ: `variant` + +int main(int argc, char **argv) { + // TODO: 为下列 ASSERT 填写正确的值 + { + std::variant var; + + var = 42; + ASSERT(std::get(var) == ?, "Variant should hold an int"); + + var = "Hello, variant!"; + ASSERT(std::get(var) == ?, "Variant should hold a string"); + } + { + std::variant var2 = 100; + std::visit([](auto &&value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + ASSERT(value == ?, "Value should be ?"); + } else if constexpr (std::is_same_v) { + ASSERT(?, "填入 true 或 false"); + } + }, + var2); + + ASSERT(std::holds_alternative(var2), "填入正确的数据类型"); + ASSERT(!std::holds_alternative(var2), "填入正确的数据类型"); + + try { + std::get(var2); + } catch (const std::bad_variant_access &e) { + std::cout << "Caught exception: " << e.what() << std::endl; + } + } + { + std::variant var3 = 3.14; + ASSERT(std::holds_alternative(var3), "填入正确的数据类型"); + ASSERT(std::get(var3) == ?, "Value should be ?"); + + var3 = "Variant supports multiple types!"; + ASSERT(std::holds_alternative(var3), "填入正确的数据类型g"); + ASSERT(std::get(var3) == ?, "String value mismatch"); + } + return 0; +} \ No newline at end of file diff --git a/exercises/37_std_deque/main.cpp b/exercises/37_std_deque/main.cpp new file mode 100755 index 000000000..3c2f87f90 --- /dev/null +++ b/exercises/37_std_deque/main.cpp @@ -0,0 +1,67 @@ +#include "../exercise.h" +#include + +// READ: `std::deque` + +int main(int argc, char **argv) { + // TODO: 为下列 ASSERT 填写正确的值 + { + std::deque dq = {1, 2, 3}; + // TODO: 使用 `push_front` 和 `push_back` 添加正确元素 + dq.push_front(?); + dq.push_back(?); + + ASSERT(dq.front() == 0, "Front element should be 0"); + ASSERT(dq.back() == 4, "Back element should be 4"); + + dq.pop_front(); + dq.pop_back(); + + ASSERT(dq.size() == ?, "Deque size should be ? after popping"); + ASSERT(dq[0] == ? && dq[1] == ? && dq[2] == ?, "Deque elements should be ?"); + } + { + std::deque dq; + // TODO: 使用 `emplace_back` 和 `emplace_front` 添加正确元素 + dq.emplace_back(?); + dq.emplace_front(?); + + ASSERT(dq.front() == "World", "Front element should be 'World'"); + ASSERT(dq.back() == "Hello", "Back element should be 'Hello'"); + + // TODO: 使用 `erase` 删除正确元素 + dq.erase(?); + ASSERT(dq.size() == 1, "Deque size should be 1 after erase"); + ASSERT(dq.front() == "Hello", "Remaining element should be 'Hello'"); + } + { + std::deque dq = {10, 20, 30}; + int sum = 0; + for (const auto &val : dq) { + sum += val; + } + ASSERT(sum == ?, "Sum of elements should be ?"); + } + { + // 比较运算符测试 + std::deque dq1 = {1, 2, 3}; + std::deque dq2 = {1, 2, 3}; + std::deque dq3 = {1, 2, 4}; + + ASSERT(dq1 ? dq2, "填入正确的比较运算符,== 或 != 或 < 或 >"); + ASSERT(dq1 ? dq3, "填入正确的比较运算符,== 或 != 或 < 或 >"); + ASSERT(dq1 ? dq3, "填入正确的比较运算符,== 或 != 或 < 或 >"); + } + { + // swap测试 + std::deque dq1 = {1, 2, 3}; + std::deque dq2 = {4, 5}; + + dq1.swap(dq2); + + // TODO: 为 ? 填写正确的值 + ASSERT(dq1.size() == ? && dq1[0] == ? && dq1[1] == ?, "the contents of dq1 should be ?"); + ASSERT(dq2.size() == ? && dq2[0] == ? && dq2[1] == ? && dq2[2] == ?, "the contents of dq2 should be ?"); + } + return 0; +} diff --git a/exercises/38_std_forward_list/main.cpp b/exercises/38_std_forward_list/main.cpp new file mode 100755 index 000000000..7bd38f6d4 --- /dev/null +++ b/exercises/38_std_forward_list/main.cpp @@ -0,0 +1,80 @@ +#include "../exercise.h" +#include + +// READ: `std::forward_list` + +int main(int argc, char **argv) { + // TODO: 为下列 ASSERT 填写正确的值 + { + std::forward_list fl = {1, 2, 3}; + fl.push_front(0); + + // TODO: 为下面的 ASSERT 填写正确的表达式 + ASSERT(? == 0, "Front element should be 0"); + + fl.pop_front(); + ASSERT(fl.front() == ?, "Front element should now be ?"); + } + { + std::forward_list fl = {1, 3, 5}; + auto it = fl.before_begin(); + fl.insert_after(it, 0); + + ASSERT(fl.front() == ?, "Front element should be ?"); + + // TODO: 为下面的 ASSERT 填写正确的表达式 + fl.erase_after(?); + ASSERT(*std::next(fl.begin()) == 3, "Second element should be 3"); + } + { + std::forward_list fl = {10, 20, 30}; + int sum = 0; + for (const auto &val : fl) { + sum += val; + } + ASSERT(sum == ?, "Sum of elements should be ?"); + } + { + // 合并与排序 + std::forward_list fl1 = {3, 5, 7}; + std::forward_list fl2 = {2, 4, 6}; + + fl1.merge(fl2); + + // TODO: 为 ? 填写正确的值 + int expected[] = {?}; + int index = 0; + for (int val : fl1) { + ASSERT(val == expected[index++], "Merged list should be sorted"); + } + ASSERT(?, "填入 fl2.empty() 或者 !fl2.empty()"); + } + { + // 拼接操作 + std::forward_list fl1 = {1, 2, 3, 4}; + std::forward_list fl2 = {10, 20}; + + auto it = fl1.begin(); + ++it; + fl1.splice_after(it, fl2, fl2.before_begin(), fl2.end()); + + // TODO: 为 ? 填写正确的值 + int expected[] = {?}; + int index = 0; + for (int val : fl1) { + ASSERT(val == expected[index++], "Splice_after should insert elements correctly"); + } + ASSERT(?, "填入 fl2.empty() 或者 !fl2.empty()"); + } + { + // 比较运算符测试 + std::forward_list fl1 = {1, 2, 3}; + std::forward_list fl2 = {1, 2, 3}; + std::forward_list fl3 = {1, 2, 4}; + + ASSERT(fl1 ? fl2, "填入正确的比较运算符,== 或 != 或 < 或 >"); + ASSERT(fl1 ? fl3, "填入正确的比较运算符,== 或 != 或 < 或 >"); + ASSERT(fl1 ? fl3, "填入正确的比较运算符,== 或 != 或 < 或 >"); + } + return 0; +} diff --git a/exercises/39_std_fs/main.cpp b/exercises/39_std_fs/main.cpp new file mode 100755 index 000000000..07f0fc0ee --- /dev/null +++ b/exercises/39_std_fs/main.cpp @@ -0,0 +1,45 @@ +#include "../exercise.h" +#include +#include + +// READ: `std::filesystem` + +int main(int argc, char **argv) { + namespace fs = std::filesystem; + + // TODO: 为下列 ASSERT 填写正确的值 + { + // 获取当前路径 + fs::path current_path = fs::current_path(); + ASSERT(?, "填入 current_path.empty() 或者 !current_path.empty()"); + } + { + fs::path test_dir = "test_directory"; + fs::create_directory(test_dir); + ASSERT(?, "填入 fs::exists(test_dir) 或者 !fs::exists(test_dir)"); + + fs::remove(test_dir); + ASSERT(?, "填入 fs::exists(test_dir) 或者 !fs::exists(test_dir)"); + } + { + fs::path test_file = "test_file.txt"; + std::ofstream ofs(test_file); + ofs << "Hello, filesystem!"; + ofs.close(); + + ASSERT(?, "填入 fs::exists(test_file) 或者 !fs::exists(test_file)"); + + std::ifstream ifs(test_file); + std::string content; + std::getline(ifs, content); + ASSERT(content == ?, "File content should match the written content"); + ifs.close(); + + auto file_size = fs::file_size(test_file); + ASSERT(file_size == ?, "File size should be ?"); + + fs::remove(test_file); + ASSERT(!fs::exists(test_file), "File should not exist after removal"); + } + return 0; +} diff --git a/exercises/40_std_thread/main.cpp b/exercises/40_std_thread/main.cpp new file mode 100755 index 000000000..038e1896c --- /dev/null +++ b/exercises/40_std_thread/main.cpp @@ -0,0 +1,119 @@ +#include "../exercise.h" +#include +#include +#include +#include +#include +#include +#include + +// READ: `std::thread` + +void print_message(const std::string &message) { + std::cout << message << std::endl; +} + +void accumulate_range(const std::vector &nums, int start, int end, int &result) { + result = std::accumulate(nums.begin() + start, nums.begin() + end, 0); +} + +void detached_task() { + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "Detached thread completed after 1 second." << std::endl; +} + +int main(int argc, char **argv) { + // TODO: 为下列 ASSERT 填写正确的值 + { + std::thread t(print_message, "Hello from thread!"); + t.join(); + } + { + std::vector nums(100, 1); + int result1 = 0, result2 = 0; + + // TODO: 为下面填写正确的值 + std::thread t1(accumulate_range, std::ref(nums), 0, ?, std::ref(result1)); + std::thread t2(accumulate_range, std::ref(nums), ?, 100, std::ref(result2)); + + t1.join(); + t2.join(); + + ASSERT(result1 == 50, "First half sum should be 50"); + ASSERT(result2 == 50, "Second half sum should be 50"); + ASSERT(result1 + result2 == 100, "Total sum should be 100"); + } + { + int counter = 0; + // TODO: 为下面线程填写正确的入口匿名函数,修改 counter 的值以通过测试 + std::thread t(?); + t.join(); + ASSERT(counter == 10, "Counter should be 10 after thread execution"); + } + { + std::thread t(detached_task); + t.detach(); + std::this_thread::sleep_for(std::chrono::seconds(2)); + std::cout << "Main thread completed after 2 seconds." << std::endl; + } + { + std::thread t([]() { + std::cout << "Thread ID: " << std::this_thread::get_id() << std::endl; + }); + t.join(); + } + { + std::atomic counter{0}; + const int iterations = 1000; + + auto increment = [&counter, iterations]() { + for (int i = 0; i < iterations; ++i) { + counter.fetch_add(1, std::memory_order_relaxed); + } + }; + + std::vector threads; + for (int i = 0; i < 10; ++i) { + // TODO: 为每个线程填写正确的入口匿名函数,修改 counter 的值以通过测试 + + } + + for (auto &t : threads) { + t.join(); + } + + ASSERT(counter == ?, "Atomic counter should be ?"); + } + { + std::promise p; + std::future f = p.get_future(); + + // TODO: 填写需要捕获的变量 + std::thread t([?]() { + std::this_thread::sleep_for(std::chrono::seconds(1)); + p.set_value_at_thread_exit(42); + }); + + ASSERT(f.get() == ?, "Future should get value ? from promise"); + + t.join(); + } + { + thread_local int thread_local_counter = 0; + + auto inc_local = []() { + for (int i = 0; i < 1000; ++i) { + ++thread_local_counter; + } + }; + + std::thread t1(inc_local); + std::thread t2(inc_local); + + t1.join(); + t2.join(); + + ASSERT(thread_local_counter == ?, "Thread local counter in main thread should be ?"); + } + return 0; +} diff --git a/exercises/41_std_mutex/main.cpp b/exercises/41_std_mutex/main.cpp new file mode 100755 index 000000000..aadd112d6 --- /dev/null +++ b/exercises/41_std_mutex/main.cpp @@ -0,0 +1,111 @@ +#include "../exercise.h" +#include // 修复:缺少 std::condition_variable +#include +#include // 修复:缺少 std::mutex +#include // 修复:缺少 std::queue +#include +#include + +// READ: `std::mutex` + +std::mutex mtx; +int counter = 0; + +void increment_counter(int iterations) { + for (int i = 0; i < iterations; ++i) { + //TODO: 使用 std::lock_guard 保护对 counter 的访问 + ? + ++counter; + } +} + +int main(int argc, char **argv) { + // TODO: 为下列 ASSERT 填写正确的值 + { + // 基本使用 + std::thread t1(increment_counter, 1000); + std::thread t2(increment_counter, 1000); + + t1.join(); + t2.join(); + + ASSERT(counter == ?, "Counter should be ? after both threads finish"); + } + { + std::vector shared_data; + auto append_data = [&shared_data](int value) { + std::lock_guard lock(mtx); + shared_data.push_back(value); + }; + + std::thread t1(append_data, 1); + std::thread t2(append_data, 2); + + t1.join(); + t2.join(); + + ASSERT(shared_data.size() == ?, "Shared data should contain ? elements"); + ASSERT(?, "判断 shared_data 中的值,如(shared_data[0] == 1 && shared_data[1] == 2)"); + } + { + std::queue data_queue; + std::mutex mtx; + std::condition_variable cv; + bool done = false; + int received = 0; + + std::thread producer([&]() { + for (int i = 1; i <= 5; ++i) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::lock_guard lock(mtx); + data_queue.push(i); + cv.notify_one(); + } + done = true; + cv.notify_one(); + }); + + std::thread consumer([&]() { + while (true) { + std::unique_lock lock(mtx); + cv.wait(lock, [&] { return !data_queue.empty() || done; }); + // TODO: 为消费者进程设置正确的行为,注意:循环退出条件 + + } + }); + + producer.join(); + consumer.join(); + + ASSERT(received == 15, "Consumer should receive sum 1+2+3+4+5=15"); + } + { + std::mutex fork1, fork2; + int eaten = 0; + + std::thread philosopher1([&]() { + std::lock_guard lock1(fork1); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + // TODO: 为 fork2 加锁 + + ++eaten; + }); + + std::thread philosopher2([&]() { + std::unique_lock lock1(fork2, std::defer_lock); + std::unique_lock lock2(fork1, std::defer_lock); + // TODO: 原子操作为 fork1、 fork2 加锁 + // 思考为什么这样可以避免死锁 + + ++eaten; + }); + + philosopher1.join(); + philosopher2.join(); + + ASSERT(eaten == ?, "Both philosophers should have eaten"); + } + + + return 0; +} diff --git a/exercises/xmake.lua b/exercises/xmake.lua index 0c3b11bfd..9b7c693e2 100644 --- a/exercises/xmake.lua +++ b/exercises/xmake.lua @@ -141,3 +141,35 @@ target("exercise33") add_files("33_std_accumulate/main.cpp") -- TODO: lambda; deque; forward_list; fs; thread; mutex; + +-- lambda +target("exercise34") + add_files("34_lambda/main.cpp") + +-- optional +target("exercise35") + add_files("35_optional/main.cpp") + +-- variant +target("exercise36") + add_files("36_variant/main.cpp") + +-- std::deque +target("exercise37") + add_files("37_std_deque/main.cpp") + +-- std::forward_list +target("exercise38") + add_files("38_std_forward_list/main.cpp") + +-- std::filesystem +target("exercise39") + add_files("39_std_fs/main.cpp") + +-- std::thread +target("exercise40") + add_files("40_std_thread/main.cpp") + +-- std::mutex +target("exercise41") + add_files("41_std_mutex/main.cpp")