C++复习核心精华

news2025/5/27 17:18:57

一、内存管理与智能指针

内存管理是C++区别于其他高级语言的关键特性,掌握好它就掌握了C++的灵魂。

1. 原始指针与内存泄漏

先来看看传统C++的内存管理方式:

void oldWay() {

    int* p = new int(42);  // 分配内存

    

    // 如果这里发生异常或提前return,下面的delete可能不会执行

    // 其他代码...

    

    delete p;  // 释放内存

    p = nullptr;  // 避免悬空指针

}

这种方式有什么问题呢?太容易出错了!忘记delete、出现异常、提前返回...都会导致内存泄漏。就像你把菜做到一半,突然停电了,灶台上的火忘了关,后果很严重啊!

2. RAII原则与智能指针详解

C++引入了RAII原则(Resource Acquisition Is Initialization),资源的获取与初始化同时进行,资源的释放与对象销毁同时进行。这就像是给你的厨房装了个自动灭火器,不管发生什么,都能自动处理。

智能指针就是RAII的典型应用:

std::unique_ptr

独占所有权的智能指针,不能复制,但可以移动。

void betterWay() {

    std::unique_ptr<int> p1 = std::make_unique<int>(42);  // C++14引入

    // 或者在C++11中:std::unique_ptr<int> p1(new int(42));

    

    // 即使这里发生异常,p1也会自动释放内存

    

    // 独占所有权,不能复制

    // std::unique_ptr<int> p2 = p1;  // 编译错误!

    

    // 但可以转移所有权

    std::unique_ptr<int> p3 = std::move(p1);  // p1现在为空

    

    // 离开作用域时,p3自动释放内存

}

unique_ptr的内部实现非常轻量,几乎没有性能开销,是最常用的智能指针。就像是你的私人助手,只为你一个人服务,效率极高。

std::shared_ptr与引用计数

共享所有权的智能指针,通过引用计数机制实现。

void sharedOwnership() {

    // 创建一个shared_ptr

    std::shared_ptr<int> sp1 = std::make_shared<int>(100);

    std::cout << "引用计数: " << sp1.use_count() << std::endl;  // 输出:1

    

    {

        // 创建sp1的副本,共享所有权

        std::shared_ptr<int> sp2 = sp1;

        std::cout << "引用计数: " << sp1.use_count() << std::endl;  // 输出:2

        

        // 修改值,两个指针指向同一个对象

        *sp2 = 200;

        std::cout << "sp1指向的值: " << *sp1 << std::endl;  // 输出:200

    }  // sp2离开作用域,引用计数减1

    

    std::cout << "引用计数: " << sp1.use_count() << std::endl;  // 输出:1

}  // sp1离开作用域,引用计数减为0,内存被释放

shared_ptr内部维护两块内存:一个是数据本身,一个是控制块(包含引用计数等信息)。这有点像合租房子,大家共同负责,最后一个离开的人负责关灯锁门。

std::weak_ptr与循环引用问题

weak_ptr不增加引用计数,用于解决循环引用问题。

class Node {

public:

    std::string name;

    std::shared_ptr<Node> next;  // 指向下一个节点

    std::weak_ptr<Node> prev;    // 指向前一个节点(弱引用)

    

    Node(const std::string& n) : name(n) {}

    

    ~Node() {

        std::cout << "销毁节点: " << name << std::endl;

    }

};

void circularReference() {

    auto node1 = std::make_shared<Node>("Node1");

    auto node2 = std::make_shared<Node>("Node2");

    

    // 创建循环引用

    node1->next = node2;

    node2->prev = node1;  // 弱引用不会增加引用计数

    

    // 使用弱引用

    if (auto temp = node2->prev.lock()) {  // 转换为shared_ptr

        std::cout << "前一个节点是: " << temp->name << std::endl;

    }

}  // 函数结束时,两个节点都能被正确释放

如果prev也使用shared_ptr,就会形成循环引用,导致内存泄漏。这就像两个人互相等对方先离开,结果谁也走不了。

3. 自定义删除器

有时我们需要在释放资源时执行特定操作,可以使用自定义删除器:

// 文件资源管理

void customDeleter() {

    // 自定义删除器,确保文件正确关闭

    auto fileCloser = [](FILE* fp) {

        if (fp) {

            std::cout << "关闭文件" << std::endl;

            fclose(fp);

        }

    };

    

    // 使用自定义删除器的智能指针

    std::unique_ptr<FILE, decltype(fileCloser)> filePtr(fopen("data.txt", "r"), fileCloser);

    

    if (filePtr) {

        // 使用文件...

        char buffer[100];

        fread(buffer, 1, sizeof(buffer), filePtr.get());

    }

    

    // 离开作用域时,fileCloser会被调用

}

这个例子完美展示了RAII的威力,无论函数如何退出,文件都会被正确关闭。就像雇了专业保洁员,走的时候一定会把屋子打扫干净。

二、模板编程的艺术

模板是C++最强大的特性之一,让你写出既通用又高效的代码。它不仅仅是代码复用工具,更是元编程的基础。

1. 函数模板深入理解

基本函数模板我们都了解,但你知道模板还能做这些事吗?

// 可变参数模板

template<typename T>

T sum(T value) {

    return value;

}

template<typename T, typename... Args>

T sum(T first, Args... args) {

    return first + sum(args...);

}

// 使用

int total = sum(1, 2, 3, 4, 5);  // 返回15

std::string s = sum(std::string("Hello"), " ", "World");  // 返回"Hello World"

递归模板展开是一个非常强大的技术,这段代码的展开过程就像俄罗斯套娃,层层展开,最终计算出结果。

2. 类模板特化

模板特化允许我们为特定类型提供特殊实现:

// 主模板

template<typename T>

class DataHandler {

public:

    void process(T data) {

        std::cout << "处理通用数据: " << data << std::endl;

    }

};

// 针对std::string的完全特化

template<>

class DataHandler<std::string> {

public:

    void process(std::string data) {

        std::cout << "处理字符串: " << data << std::endl;

        // 字符串特有的处理逻辑...

    }

};

// 部分特化(针对指针类型)

template<typename T>

class DataHandler<T*> {

public:

    void process(T* data) {

        if (data) {

            std::cout << "处理指针指向的数据: " << *data << std::endl;

        } else {

            std::cout << "空指针!" << std::endl;

        }

    }

};

模板特化就像餐厅里的"定制菜单",根据不同的"食客"(类型)提供量身定制的"服务"(实现)。

3. SFINAE与类型萃取

SFINAE (Substitution Failure Is Not An Error) 是模板元编程的重要技术,允许编译器在模板实例化失败时继续尝试其他重载。

// 检查类型是否有size()成员函数

template<typename T>

struct has_size {

private:

    template<typename C> static constexpr auto test(int) 

        -> decltype(std::declval<C>().size(), bool()) { return true; }

    template<typename C> static constexpr bool test(...) { return false; }

    

public:

    static constexpr bool value = test<T>(0);

};

// 根据类型特性选择不同实现

template<typename Container>

typename std::enable_if<has_size<Container>::value, void>::type

printSize(const Container& c) {

    std::cout << "容器大小: " << c.size() << std::endl;

}

template<typename T>

typename std::enable_if<!has_size<T>::value, void>::type

printSize(const T&) {

    std::cout << "此类型没有size()方法" << std::endl;

}

在C++17中,我们可以使用if constexpr简化这种代码:

template<typename Container>

void printSize(const Container& c) {

    if constexpr (has_size<Container>::value) {

        std::cout << "容器大小: " << c.size() << std::endl;

    } else {

        std::cout << "此类型没有size()方法" << std::endl;

    }

}

这种技术就像是编译时的"魔法侦探",能够根据类型的特性自动选择最合适的实现路径。

三、STL深度剖析

STL是C++标准库的核心部分,掌握它可以避免重复造轮子,大幅提高开发效率。

1. 容器性能对比与选择指南

不同容器有不同的性能特点,选择合适的容器至关重要:

容器随机访问插入 / 删除 (中间)插入 / 删除 (首 / 尾)查找特点
vectorO(1)O(n)O(1) 尾部O(n)连续内存,缓存友好
listO(n)O(1)O(1)O(n)双向链表,稳定迭代器
dequeO(1)O(n)O(1) 首尾O(n)分段连续内存
set/mapO(log n)O(log n)O(log n)O(log n)红黑树实现,有序
unordered_set/mapO(1) 平均O(1) 平均O(1) 平均O(1) 平均哈希表实现,无序
// 性能敏感场景选择指南

void containerChoice() {

    // 1. 频繁随机访问,较少插入删除 -> vector

    std::vector<int> v;

    

    // 2. 频繁在两端操作 -> deque

    std::deque<int> d;

    

    // 3. 频繁在中间插入删除 -> list

    std::list<int> l;

    

    // 4. 需要有序并快速查找 -> set/map

    std::map<std::string, int> m;

    

    // 5. 需要最快的查找,不要求有序 -> unordered_set/map

    std::unordered_map<std::string, int> um;

}

选择合适的容器就像选择合适的工具,木匠不会用锤子切木头,也不会用锯子钉钉子。

2. 算法与迭代器配合使用

STL的强大在于算法与容器的解耦,通过迭代器连接:

void algorithmDemo() {

    std::vector<int> numbers = {1, 5, 3, 4, 2};

    

    // 查找

    auto it = std::find(numbers.begin(), numbers.end(), 3);

    if (it != numbers.end()) {

        std::cout << "找到: " << *it << " 位置: " << std::distance(numbers.begin(), it) << std::endl;

    }

    

    // 排序

    std::sort(numbers.begin(), numbers.end());

    

    // 二分查找(要求已排序)

    bool exists = std::binary_search(numbers.begin(), numbers.end(), 3);

    

    // 变换

    std::vector<int> squared;

    std::transform(numbers.begin(), numbers.end(), std::back_inserter(squared),

                  [](int x) { return x * x; });

    

    // 累加

    int sum = std::accumulate(numbers.begin(), numbers.end(), 0);

    

    // 自定义排序

    std::sort(numbers.begin(), numbers.end(), [](int a, int b) {

        return std::abs(a) < std::abs(b);  // 按绝对值排序

    });

}

3. 自定义容器的迭代器

理解迭代器设计可以帮助我们更好地使用STL,甚至为自定义容器实现迭代器:

// 简单的环形缓冲区

template<typename T, size_t Size>

class CircularBuffer {

private:

    T data_[Size];

    size_t head_ = 0;

    size_t tail_ = 0;

    size_t size_ = 0;

    

public:

    // 迭代器实现

    class iterator {

    private:

        CircularBuffer<T, Size>* buffer_;

        size_t index_;

        size_t count_;

        

    public:

        // 迭代器类型定义(满足STL要求)

        using iterator_category = std::forward_iterator_tag;

        using value_type = T;

        using difference_type = std::ptrdiff_t;

        using pointer = T*;

        using reference = T&;

        

        iterator(CircularBuffer<T, Size>* buffer, size_t index, size_t count)

            : buffer_(buffer), index_(index), count_(count) {}

        

        // 迭代器操作

        T& operator*() { return buffer_->data_[index_]; }

        

        iterator& operator++() {

            index_ = (index_ + 1) % Size;

            ++count_;

            return *this;

        }

        

        bool operator!=(const iterator& other) const {

            return count_ != other.count_;

        }

    };

    

    // 容器方法

    void push(const T& value) {

        data_[tail_] = value;

        tail_ = (tail_ + 1) % Size;

        if (size_ < Size) {

            ++size_;

        } else {

            head_ = (head_ + 1) % Size;  // 覆盖最老的元素

        }

    }

    

    // 提供迭代器

    iterator begin() { return iterator(this, head_, 0); }

    iterator end() { return iterator(this, head_, size_); }

};

// 使用示例

void customContainerDemo() {

    CircularBuffer<int, 5> buffer;

    for (int i = 0; i < 7; ++i) {

        buffer.push(i);

    }

    

    // 此时缓冲区包含:2, 3, 4, 5, 6

    

    // 使用for-each循环(需要begin/end支持)

    for (const auto& value : buffer) {

        std::cout << value << " ";  // 输出:2 3 4 5 6

    }

    

    // 也可以与STL算法配合使用

    auto sum = std::accumulate(buffer.begin(), buffer.end(), 0);

    std::cout << "\n总和: " << sum << std::endl;  // 输出:20

}

自定义迭代器需要满足特定的接口要求,这样才能与STL算法无缝配合。就像设计插头和插座,只要遵循标准,任何设备都能正常工作。

四、现代C++特性(C++11/14/17/20)

现代C++引入了大量新特性,极大提升了开发效率和代码质量。

1. 移动语义与右值引用

移动语义允许我们在不需要深拷贝的情况下转移资源所有权,大幅提升性能:

class BigData {

private:

    int* data_;

    size_t size_;

    

public:

    // 构造函数

    BigData(size_t size) : size_(size) {

        data_ = new int[size];

        std::cout << "分配 " << size << " 个整数" << std::endl;

    }

    

    // 析构函数

    ~BigData() {

        delete[] data_;

        std::cout << "释放内存" << std::endl;

    }

    

    // 拷贝构造函数(深拷贝)

    BigData(const BigData& other) : size_(other.size_) {

        data_ = new int[size_];

        std::memcpy(data_, other.data_, size_ * sizeof(int));

        std::cout << "拷贝 " << size_ << " 个整数(昂贵操作)" << std::endl;

    }

    

    // 移动构造函数

    BigData(BigData&& other) noexcept : data_(other.data_), size_(other.size_) {

        other.data_ = nullptr;  // 防止源对象释放内存

        other.size_ = 0;

        std::cout << "移动资源(快速操作)" << std::endl;

    }

    

    // 移动赋值运算符

    BigData& operator=(BigData&& other) noexcept {

        if (this != &other) {

            delete[] data_;  // 释放当前资源

            

            // 窃取资源

            data_ = other.data_;

            size_ = other.size_;

            

            // 将源对象置于有效但可析构状态

            other.data_ = nullptr;

            other.size_ = 0;

            

            std::cout << "移动赋值(快速操作)" << std::endl;

        }

        return *this;

    }

};

// 演示移动语义优势

void moveSemantics() {

    std::vector<BigData> v;

    

    std::cout << "创建临时对象并添加到vector:" << std::endl;

    v.push_back(BigData(1000000));  // 使用移动构造函数,避免深拷贝

    

    std::cout << "\n创建命名对象:" << std::endl;

    BigData d1(1000000);

    

    std::cout << "\n复制添加到vector:" << std::endl;

    v.push_back(d1);  // 使用拷贝构造函数,进行深拷贝

    

    std::cout << "\n移动添加到vector:" << std::endl;

    v.push_back(std::move(d1));  // 显式使用移动语义

    // 注意:此时d1已被移动,处于有效但未指定状态,不应再使用它的值

}

移动语义就像是把一整本书直接交给别人,而不是复印一份再给他。在处理大型资源时,这种差异极其显著。

2. 完美转发与通用引用

完美转发允许函数模板精确地传递参数,保持其值类别(左值/右值):

// 工厂函数示例

template<typename T, typename... Args>

std::unique_ptr<T> make_unique(Args&&... args) {

    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));

}

// 完美转发包装器

template<typename Func, typename... Args>

auto forwardingWrapper(Func&& func, Args&&... args) 

    -> decltype(func(std::forward<Args>(args)...)) {

    std::cout << "转发参数到函数" << std::endl;

    return func(std::forward<Args>(args)...);

}

void perfectForwarding() {

    auto print = [](const std::string& s) { 

        std::cout << "左值: " << s << std::endl; 

        return s.length();

    };

    

    auto printRValue = [](std::string&& s) { 

        std::cout << "右值: " << s << std::endl; 

        return s.length();

    };

    

    std::string str = "Hello";

    

    // 转发左值

    forwardingWrapper(print, str);

    

    // 转发右值

    forwardingWrapper(printRValue, std::move(str));

    

    // 创建对象并完美转发参数

    auto p = make_unique<std::vector<int>>(5, 10);  // 创建包含5个10的vector

}

完美转发就像是一个完美的中间人,既不添加任何东西,也不减少任何东西,原封不动地传递参数。

3. Lambda表达式与捕获技巧

Lambda表达式让函数式编程在C++中变得简单优雅:

void lambdaExamples() {

    int x = 10;

    

    // 基本lambda

    auto add = [](int a, int b) { return a + b; };

    std::cout << "5 + 3 = " << add(5, 3) << std::endl;

    

    // 捕获变量

    auto addX = [x](int a) { return a + x; };

    std::cout << "5 + x = " << addX(5) << std::endl;

    

    // 引用捕获(可修改外部变量)

    auto incrementX = [&x]() { x++; };

    incrementX();

    std::cout << "x现在是: " << x << std::endl;  // 输出:11

    

    // 混合捕获

    int y = 20;

    auto calculate = [x, &y](int a) { 

        y += a;  // 修改y

        return x * y;  // 使用x的副本

    };

    std::cout << "计算结果: " << calculate(5) << std::endl;

    std::cout << "y现在是: " << y << std::endl;  // y被修改

    

    // 捕获this指针

    struct Counter {

        int value = 0;

        

        auto increment() {

            // 捕获this指针,可访问成员变量

            return [this]() { ++value; };

        }

        

        void print() {

            std::cout << "计数: " << value << std::endl;

        }

    };

    

    Counter c;

    auto inc = c.increment();

    inc();

    inc();

    c.print();  // 输出:计数: 2

    

    // 初始化捕获(C++14)

    auto sum = [sum = 0](int value) mutable {

        sum += value;

        return sum;

    };

    

    std::cout << sum(1) << std::endl;  // 1

    std::cout << sum(2) << std::endl;  // 3

    std::cout << sum(3) << std::endl;  // 6

}

Lambda表达式就像是随手写下的小纸条,简洁而直接,让代码更加紧凑易读。

4. constexpr与编译期计算

constexpr允许在编译期执行计算,提高运行时性能:

// 编译期计算斐波那契数列

constexpr int fibonacci(int n) {

    return (n <= 1) ? n : fibonacci(n-1) + fibonacci(n-2);

}

// 编译期计算阶乘

constexpr int factorial(int n) {

    return (n <= 1) ? 1 : n * factorial(n-1);

}

void constexprDemo() {

    // 编译期计算

    constexpr int fib10 = fibonacci(10);

    constexpr int fact5 = factorial(5);

    

    std::cout << "斐波那契(10) = " << fib10 << std::endl;

    std::cout << "阶乘(5) = " << fact5 << std::endl;

    

    // 编译期数组大小

    constexpr int size = factorial(5);

    int arr[size];  // 使用编译期常量作为数组大小

    

    // C++17: constexpr if

    template<typename T>

    auto getValue(T t) {

        if constexpr (std::is_pointer_v<T>) {

            return *t;  // 指针类型

        } else {

            return t;   // 非指针类型

        }

    }

    

    int x = 42;

    int* p = &x;

    

    std::cout << getValue(x) << std::endl;  // 42

    std::cout << getValue(p) << std::endl;  // 42

}

constexpr就像是提前做好的作业,编译器在编译时就把结果算出来了,运行时直接使用结果,不需要再计算。

总结

记住,C++的威力不仅在于它的特性,更在于如何巧妙地组合这些特性,解决实际问题。就像武术高手,招式并不是最重要的,关键是如何融会贯通,形成自己的"功夫"。

希望这些深度解析能帮助你更好地理解C++的精髓。有什么不明白的地方,或者想要了解的其他C++话题,随时告诉我!我们一起在C++的海洋中探索更多奥秘!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2386103.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MCP技术体系介绍

MCP,全称时Model Context Protocol,模型上下文协议,由Claude母公司Anthropic于2014年11月正式提出。 MCP的核心作用是统一了Agent开发过程中大模型调用外部工具的技术实现流程,从而大幅提高Agent的开发效率。在MCP诞生之前,不同外部工具各有不同的调用方法。 要连接这些…

我的第1个爬虫程序——豆瓣Top250爬虫的详细步骤指南

我的第1个爬虫程序——豆瓣Top250爬虫的详细步骤指南 一、创建隔离开发环境 1. 使用虚拟环境&#xff08;推荐venv&#xff09; # 在项目目录打开终端执行 python -m venv douban_env # 创建虚拟环境 source douban_env/bin/activate # Linux/macOS激活 douban_env\Scri…

Selenium 测试框架 - C#

🚀Selenium C# 自动化测试实战:以百度搜索为例 本文将通过一个简单示例,手把手教你如何使用 Selenium + C# 实现百度搜索自动化测试。适合初学者快速上手,也适合作为企业 UI 自动化测试模板参考。 🧩 一、安装必要 NuGet 包 在 Visual Studio 的 NuGet 管理器中安装以下…

JavaWeb:SpringBoot工作原理详解

一、SpringBoot优点 1.为所有Spring开发者更快的入门 2.开箱即用&#xff0c;提供各种默认配置来简化项目配置 3.内嵌式容器简化Web项目 4.没有冗余代码生成和XML配置的要求 二、SpringBoot 运行原理 2.1. pom.xml spring-boot-dependencies: 核心依赖在父工程中&#xff1b;…

dify_plugin数据库中的表总结

本文使用dify-plugin-daemon v0.1.0版本&#xff0c;主要对dify_plugin数据库中的数据表进行了总结。 一.agent_strategy_installations 源码位置&#xff1a;dify-plugin-daemon\internal\types\models\agent.go type AgentStrategyInstallation struct {ModelTenantID …

HarmonyOS学习——UIAbility组件(上)

UIAbility组件概述 应用程序有几种界面交互形式 UIAbility&#xff1a;应用程序的入口 概述 UIAbility组件是一种包含UI的应用组件&#xff0c;主要用于和用户交互。 UIAbility的设计理念&#xff1a; 原生支持应用组件级的跨端迁移和多端协同。 支持多设备和多窗口形态。…

【Linux】磁盘空间不足

错误提示: no space left on device 经典版&#xff08;block占用&#xff09; 模拟 dd if/dev/zero of/var/log/nginx.log bs1M count2000排查 #1. df -h 查看哪里空间不足,哪个分区#2. du -sh详细查看目录所占空间 du -sh /* 排查占用空间大的目录 du -sh /var/* du…

持续更新 ,GPT-4o 风格提示词案例大全!附使用方式

本文汇集了各类4o风格提示词的精选案例&#xff0c;从基础指令到复杂任务&#xff0c;从创意写作到专业领域&#xff0c;为您提供全方位的参考和灵感。我们将持续更新这份案例集&#xff0c;确保您始终能够获取最新、最有效的提示词技巧。 让我们一起探索如何通过精心设计的提…

QStandardItemModel的函数和信号介绍

前言 Qt版本:6.8.0 QStandardItem函数介绍 函数 部分函数有不同的重载来适应不同的模型,例如appendrow 构造函数与析构函数 1. QStandardItemModel(QObject *parent nullptr) 说明&#xff1a;创建一个空的模型&#xff08;0行0列&#xff09;。参数&#xff1a; parent&…

Python 内存管理机制详解:从分配到回收的全流程剖析

在 Python 编程中&#xff0c;开发者无需像 C/C 那样手动分配和释放内存&#xff0c;但这并不意味着内存管理与我们无关。了解 Python 内存管理机制&#xff0c;能帮助我们编写出更高效、稳定的代码。接下来&#xff0c;我们将深入剖析 Python 内存管理的各个环节&#xff0c;并…

【报错】Error attempting to get column ‘created_time‘ from result set.解决方法

postman报错以下内容 {"code": "500","msg": "查询失败&#xff1a;Error attempting to get column created_time from result set. Cause: java.sql.SQLFeatureNotSupportedException\n; null; nested exception is java.sql.SQLFeatur…

Google 推出 Flow —— AI 电影制作新平台

这周, Google I/O 2025 大会上发布了一些重磅 AI 公告。 他们推出了全新的图像模型 Imagen 4,还发布了升级版视频生成器 Veo 3、升级版 Gemini Pro 模型,以及一系列其他令人印象深刻的更新。 但将所有这些生成式媒体工具整合在一起的,是他们称为 Flow 的平台。 什么是 F…

跨链风云:打破区块链孤岛,实现价值自由流转

嘿&#xff0c;各位技术爱好者们&#xff01;今天我们来聊一个区块链领域非常火热且至关重要的话题——跨链技术。你可能听说过&#xff0c;比如想把在波场&#xff08;Tron&#xff09;链上的USDT转移到以太坊&#xff08;Ethereum&#xff09;网络上&#xff0c;这个过程就涉…

鸿蒙开发:了解$$运算符

前言 本文基于Api13 有这样一个需求&#xff0c;一个Text组件&#xff0c;一个TextInput组件&#xff0c;要求Text组件同步展示TextInput组件里的内容&#xff0c;也就是TextInput组件输入什么内容&#xff0c;就要在Text组件里展示什么内容&#xff0c;这个需求如何实现呢&…

基于CEEMDAN-Transformer-BiLSTM的多特征风速气候预测的完整实现方案及PyTorch源码解析

基于CEEMDAN-Transformer-BiLSTM的多特征风速气候预测的完整实现方案及PyTorch源码解析 一、模型架构设计 1.1 整体框架 该模型采用三级架构设计&#xff08;图1&#xff09;&#xff1a; CEEMDAN分解层&#xff1a;对非平稳风速序列进行自适应分解多模态特征融合模块&#…

基于TypeScript的全栈待办事项应用Demo

Demo地址&#xff1a;git clone https://gitcode.com/rmbnetlife/todo-app.git Todo List 应用 这是一个基于TypeScript的全栈待办事项应用&#xff0c;前端使用React&#xff0c;后端使用Node.js和Express。 项目概述 这个Todo List应用允许用户&#xff1a; 查看所有待办…

国际荐酒师(香港)协会亮相新西兰葡萄酒巡展深度参与赵凤仪大师班

国际荐酒师&#xff08;香港&#xff09;协会率团亮相2025新西兰葡萄酒巡展 深度参与赵凤仪MW“百年百碧祺”大师班 广州/上海/青岛&#xff0c;2025年5月12-16日——国际荐酒师&#xff08;香港&#xff09;协会&#xff08;IRWA&#xff09;近日率专业代表团出席“纯净独特&…

【深度学习】2. 从梯度推导到优化策略:反向传播与 SGD, Mini SGD

反向传播算法详解 1. 前向传播与输出层误差定义 假设我们考虑一个典型的前馈神经网络&#xff0c;其最后一层为 softmax 分类器&#xff0c;损失函数为交叉熵。 前向传播过程 对于某一隐藏层神经元 j j j&#xff1a; 输入&#xff1a; x i x_i xi​ 权重&#xff1a; w j…

工业软件国产化:构建自主创新生态,赋能制造强国建设

随着全球产业环境的变化和技术的发展&#xff0c;建立自主可控的工业体系成为我国工业转型升级、走新型工业化道路、推动国家制造业竞争水平提升的重要抓手。 市场倒逼与政策护航&#xff0c;国产化进程双轮驱动 据中商产业研究院预测&#xff0c;2025年中国工业软件市场规模…

UART、RS232、RS485基础知识

一、UART串口通信介绍 UART是一种采用异步串行、全双工通信方式的通用异步收发传输器功能。 硬件电路&#xff1a; •简单双向串口通信有两根通信线&#xff08;发送端TX和接收端RX&#xff09; •TX与RX要交叉连接 •当只需单向的数据传输时&#xff0c;可以只接一根通信线…