C++11学习笔记(3)——通用工具(上)(包含重要特性智能指针Smart pointer)

news2024/11/24 8:22:37

1.Pair

在C++11中,std::pair是一个模板类,用于将两个值组合成一个单元。它可以将两个不同的类型的值配对在一起,并且提供了对这对值的访问和操作。

std::pair的定义

template<class T1, class T2>
struct pair{
	T1 first;
	T2 second;
};

一些用法

创建和初始化:

可以使用构造函数或花括号初始化列表来创建和初始化std::pair对象。例如:

std::pair<int, std::string> myPair(42, "Hello");
std::pair<double, bool> anotherPair = {3.14, true};

访问成员

std::pair对象的成员可以通过.first和.second进行访问。例如:

std::pair<int, std::string> myPair(42, "Hello");
int x = myPair.first;
std::string str = myPair.second;

比较和排序

std::pair可以进行比较操作,根据.first和.second的值进行比较。std::pair对象可以在容器中进行排序。例如:

std::pair<int, std::string> pair1(42, "Hello");
std::pair<int, std::string> pair2(10, "World");

bool result = (pair1 < pair2);  // 比较操作
std::vector<std::pair<int, std::string>> myVector = {pair1, pair2};
std::sort(myVector.begin(), myVector.end());  // 容器排序

使用范例:

std::pair常常用于返回多个值的函数,以及在需要将两个值作为单个单元传递的情况下。例如:

std::pair<int, std::string> getPerson() {
    int age = 25;
    std::string name = "John";
    return std::make_pair(age, name);
}

std::pair<int, int> divideAndRemainder(int dividend, int divisor) {
    int quotient = dividend / divisor;
    int remainder = dividend % divisor;
    return {quotient, remainder};
}

make_pair()

无需写出类型就能生成一个pair对象,例如:

std::pair<int, char> myPair(42, "Hello");
std::make_pair(42, "Hello");

操作函数

在这里插入图片描述

std::pair提供了一种便捷的方式来组合两个值,并且可以在多种场景下使用。它是C++中常用的工具之一,用于简化代码和提高代码的可读性。

2.Tuple

Tuple扩展了pair的概念,拥有任意数量的元素,其中每个类型都可以被指定。

Tuple的定义

template<typename... Types>
class tuple;

Tuple示例

#include <iostream>
#include <tuple>

int main() {
    // 创建一个包含整数、字符串和浮点数的元组
    std::tuple<int, std::string, double> myTuple(42, "Hello", 3.14);

    // 访问元组中的元素
    int intValue = std::get<0>(myTuple);
    std::string stringValue = std::get<1>(myTuple);
    double doubleValue = std::get<2>(myTuple);

    // 修改元组中的元素
    std::get<0>(myTuple) = 100;

    // 使用tie函数将元组的元素解包到变量中
    
    int a;
    std::string b;
    double c;
    std::tie(a, b, c) = myTuple;
		//std::tie(a, std::ignore, c) = myTuple;忽略某些元素
    // 打印元组的元素
    std::cout << "Tuple elements: " << a << ", " << b << ", " << c << std::endl;
		//c++11也可直接输出myTuple
    return 0;
}

操作函数

在这里插入图片描述

std::tuple_size

用于获取std::tuple的大小。

#include <iostream>
#include <tuple>

int main() {
    std::tuple<int, std::string, double> myTuple;

    std::cout << "Tuple size: " << std::tuple_size<decltype(myTuple)>::value << std::endl;

    return 0;
}

输出结果为:Tuple size: 3,表示std::tuple中有三个元素。

std::tuple_element

用于获取std::tuple中指定位置的元素类型。


#include <iostream>
#include <tuple>

int main() {
    using MyTuple = std::tuple<int, std::string, double>;

    std::tuple_element<1, MyTuple>::type myElement;

    std::cout << "Element type: " << typeid(myElement).name() << std::endl;

    return 0;
}

输出结果为:Element type: NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE,表示std::tuple的第二个元素类型为std::string。

std::tuple_cat

用于将多个std::tuple合并成一个大的std::tuple。


#include <iostream>
#include <tuple>

int main() {
    std::tuple<int, std::string> tuple1(42, "Hello");
    std::tuple<double> tuple2(3.14);

    auto combinedTuple = std::tuple_cat(tuple1, tuple2);

    std::cout << "Combined tuple size: " << std::tuple_size<decltype(combinedTuple)>::value << std::endl;

    return 0;
}

输出结果为:Combined tuple size: 3,表示将tuple1和tuple2合并后,得到了一个包含三个元素的std::tuple。

pair与tuple

从std::pair到std::tuple的转换

可以使用std::make_tuple函数将std::pair转换为std::tuple。

#include <iostream>
#include <tuple>

int main() {
    std::pair<int, double> myPair(42, 3.14);

    std::tuple<int, double> myTuple = std::make_tuple(myPair.first, myPair.second);

    std::cout << "Tuple elements: " << std::get<0>(myTuple) << ", " << std::get<1>(myTuple) << std::endl;

    return 0;
}

在上述示例中,我们有一个std::pair<int, double>类型的对象myPair,我们可以使用std::make_tuple将其转换为std::tuple<int, double>类型的对象myTuple。

从std::tuple到std::pair的转换

可以使用std::get函数将std::tuple的元素提取出来,并使用这些元素创建一个std::pair。


#include <iostream>
#include <tuple>

int main() {
    std::tuple<int, double> myTuple(42, 3.14);

    std::pair<int, double> myPair = std::make_pair(std::get<0>(myTuple), std::get<1>(myTuple));

    std::cout << "Pair elements: " << myPair.first << ", " << myPair.second << std::endl;

    return 0;
}

在上述示例中,我们有一个std::tuple<int, double>类型的对象myTuple,我们可以使用std::get函数将其元素提取出来,并使用这些元素创建一个std::pair<int, double>类型的对象myPair。

3.Smart pointer智能指针***

指针是c/c++的重要特性,但使用中常常会出现空悬,多次删除,资源泄露等问题,避免这些问题的一个通常做法是使用智能指针。
自C++11起,标准库提供两大类智能指针:shared_ptr和unique_ptr,而auto_ptr被弃用,它们定义在< memory >内

shared_ptr

std::shared_ptr作为智能指针的一种类型,用于更安全和方便地管理动态分配的内存。std::shared_ptr使用引用计数的方式来跟踪资源的所有者,并在不再需要时自动释放资源。

以下是std::shared_ptr的基本用法和示例:

创建std::shared_ptr对象:

可以使用std::make_shared函数或直接使用std::shared_ptr的构造函数来创建std::shared_ptr对象。

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
    std::shared_ptr<int> ptr2(new int(100));

    std::cout << *ptr1 << std::endl; // 输出:42
    std::cout << *ptr2 << std::endl; // 输出:100

    return 0;
}

在上述示例中,我们使用std::make_shared创建了一个包含整数值的std::shared_ptr对象ptr1,以及使用std::shared_ptr的构造函数创建了另一个std::shared_ptr对象ptr2。

共享拥有资源:

可以将一个std::shared_ptr赋值给另一个std::shared_ptr,这样它们会共享对同一资源的拥有权。

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
    std::shared_ptr<int> ptr2 = ptr1;

    std::cout << *ptr1 << std::endl; // 输出:42
    std::cout << *ptr2 << std::endl; // 输出:42

    return 0;
}

在上述示例中,我们将ptr1赋值给ptr2,它们现在都指向同一个整数资源,并且共享对该资源的拥有权。

引用计数和资源释放:

std::shared_ptr使用引用计数来跟踪资源的所有者数量。当最后一个std::shared_ptr析构或被赋予新的值时,引用计数会减少并检查是否需要释放资源。

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
    std::shared_ptr<int> ptr2 = ptr1;
    std::shared_ptr<int> ptr3 = ptr1;

    std::cout << *ptr1 << std::endl; // 输出:42
    std::cout << *ptr2 << std::endl; // 输出:42
    std::cout << *ptr3 << std::endl; // 输出:42

    ptr1.reset();

    std::cout << std::boolalpha;
    std::cout << "ptr1 is nullptr: " << (ptr1 == nullptr) << std::endl; // 输出:true
    std::cout << "ptr2 is nullptr: " << (ptr2 == nullptr) << std::endl; // 输出:false
    std::cout << "ptr3 is nullptr: " << (ptr3 == nullptr) << std::endl; // 输出:false

    return 0;
}

在上述示例中,我们创建了三个std::shared_ptr对象ptr1、ptr2和ptr3,它们都指向同一个整数资源。当ptr1调用reset函数后,它不再拥有资源,引用计数减少并且资源被释放,但ptr2和ptr3仍然有效并拥有资源。

std::shared_ptr还提供了其他有用的成员函数,如get(返回底层指针)、use_count(返回引用计数)、unique(检查是否是唯一的拥有者)等。

使用std::shared_ptr可以有效避免内存泄漏和悬空指针等问题,并提供方便的资源管理机制。然而,要注意避免循环引用问题,因为它可能导致资源无法释放。

析构函数

std::shared_ptr的析构函数是由其模板参数指定的删除器(deleter)来执行的。可以通过提供自定义的删除器来自定义析构行为。

删除器是一个可调用对象,用于在std::shared_ptr的引用计数归零时执行资源的释放。删除器可以是函数指针、函数对象、Lambda表达式或自定义类型的对象。

以下是使用自定义删除器的示例:

#include <iostream>
#include <memory>

// 自定义删除器
struct CustomDeleter {
    void operator()(int* ptr) {
        std::cout << "Custom deleter is called" << std::endl;
        delete ptr;
    }
};

int main() {
    std::shared_ptr<int> ptr(new int(42), CustomDeleter());

    return 0;
}

在上述示例中,我们定义了一个名为CustomDeleter的结构体,其中重载了圆括号运算符,以实现自定义的删除行为。在main函数中,我们使用std::shared_ptr的构造函数来创建一个std::shared_ptr对象ptr,并将自定义删除器作为参数传递。

当std::shared_ptr的引用计数归零时,会调用自定义删除器的圆括号运算符来释放资源,并执行我们定义的自定义删除行为。在这个示例中,自定义删除器会输出一条消息,并删除指向整数的指针。

注意,当提供自定义删除器时,需要确保删除器与指针类型兼容,并遵循适当的资源释放规则。通过自定义删除器,可以实现更灵活的资源管理和析构行为,以满足特定的需求。

其他操作

在这里插入图片描述在这里插入图片描述

weak_ptr

C++11引入了std::weak_ptr作为一种智能指针类型,用于解决std::shared_ptr可能导致的循环引用问题。std::weak_ptr允许对由std::shared_ptr管理的对象进行弱引用,而不会增加引用计数,也不会阻止对象的销毁。

以下是std::weak_ptr的基本用法和示例:

创建std::weak_ptr对象

可以通过将std::shared_ptr对象转换为std::weak_ptr来创建std::weak_ptr对象。

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sharedPtr = std::make_shared<int>(42);
    std::weak_ptr<int> weakPtr = sharedPtr;

    // 输出:42
    if (auto lockedPtr = weakPtr.lock()) {
        std::cout << *lockedPtr << std::endl;
    } else {
        std::cout << "Resource has been released" << std::endl;
    }

    return 0;
}

在上述示例中,我们创建了一个std::shared_ptr对象sharedPtr来管理一个整数资源,并通过将其转换为std::weak_ptr创建了一个std::weak_ptr对象weakPtr。注意,转换为std::weak_ptr不会增加资源的引用计数。

检查std::weak_ptr是否有效并访问资源

可以使用lock()函数来检查std::weak_ptr是否有效,并获取对资源的共享访问。

#include <iostream>
#include <memory>

int main() {
    std::weak_ptr<int> weakPtr;

    {
        std::shared_ptr<int> sharedPtr = std::make_shared<int>(42);
        weakPtr = sharedPtr;

        // 输出:42
        if (auto lockedPtr = weakPtr.lock()) {
            std::cout << *lockedPtr << std::endl;
        } else {
            std::cout << "Resource has been released" << std::endl;
        }
    }

    // 输出:"Resource has been released"
    if (auto lockedPtr = weakPtr.lock()) {
        std::cout << *lockedPtr << std::endl;
    } else {
        std::cout << "Resource has been released" << std::endl;
    }

    return 0;
}

在上述示例中,我们在作用域中创建了一个std::shared_ptr对象sharedPtr,并将其转换为std::weak_ptr对象weakPtr。在作用域结束后,sharedPtr被销毁,资源被释放。在后续的代码中,我们通过调用lock()函数检查weakPtr是否有效,并访问资源。如果weakPtr有效,lock()函数将返回一个有效的std::shared_ptr对象,否则返回一个空指针。

查看资源

expired()

用于检查std::weak_ptr是否过期(即指向的资源是否已经被释放)。如果资源已经被释放,则返回true;否则返回false。

use_count()

用于获取与std::weak_ptr共享相同资源的有效std::shared_ptr对象的数量。

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sharedPtr = std::make_shared<int>(42);
    std::weak_ptr<int> weakPtr = sharedPtr;

    // 输出:1
    std::cout << "use_count: " << sharedPtr.use_count() << std::endl;

    if (weakPtr.expired()) {
        std::cout << "Resource has been released" << std::endl;
    } else {
        // 输出:42
        std::cout << "Value: " << *weakPtr.lock() << std::endl;
    }

    sharedPtr.reset();

    // 输出:0
    std::cout << "use_count: " << weakPtr.use_count() << std::endl;

    if (weakPtr.expired()) {
        std::cout << "Resource has been released" << std::endl;
    } else {
        std::cout << "Value: " << *weakPtr.lock() << std::endl;
    }

    return 0;
}

在上述示例中,我们创建了一个std::shared_ptr对象sharedPtr来管理一个整数资源,并通过将其转换为std::weak_ptr对象weakPtr来创建一个弱引用。我们使用use_count()函数来获取与sharedPtr共享相同资源的有效std::shared_ptr对象的数量。在if语句中,我们使用expired()函数检查weakPtr是否过期,然后使用lock()函数获取有效的std::shared_ptr对象并输出其值。在后续的代码中,我们通过调用reset()函数将sharedPtr置空,释放资源,并检查weakPtr是否过期。

需要注意的是,由于std::weak_ptr不增加引用计数,所以调用use_count()函数返回的是与其共享资源的有效std::shared_ptr对象的数量。

其他操作

在这里插入图片描述

通过使用std::weak_ptr,我们可以避免std::shared_ptr可能导致的循环引用问题,并更灵活地管理资源的生命周期。

unique_ptr

std::unique_ptr是独占所有权的智能指针,意味着同一时间只能有一个std::unique_ptr拥有指针所指向的对象。当unique_ptr被销毁,其所指向的对象也会自动被销毁。

以下是std::unique_ptr的基本用法和示例:

创建std::unique_ptr对象

可以使用std::make_unique函数或直接使用std::unique_ptr的构造函数来创建std::unique_ptr对象。

#include <iostream>
#include <memory>

int main() {
    std::unique_ptr<int> uniquePtr1 = std::make_unique<int>(42);
    std::unique_ptr<int> uniquePtr2(new int(100));

    // 输出:42
    std::cout << *uniquePtr1 << std::endl;

    // 输出:100
    std::cout << *uniquePtr2 << std::endl;

    return 0;
}

在上述示例中,我们使用std::make_unique函数和构造函数分别创建了两个std::unique_ptr对象uniquePtr1和uniquePtr2来管理两个整数资源。注意,std::make_unique是C++14引入的函数,如果你使用的是C++11,可以直接使用std::unique_ptr的构造函数。

执行所有权的转移

std::unique_ptr具有独占所有权的特性,可以通过移动语义将所有权从一个std::unique_ptr转移到另一个std::unique_ptr。

#include <iostream>
#include <memory>

int main() {
    std::unique_ptr<int> uniquePtr1 = std::make_unique<int>(42);
    std::unique_ptr<int> uniquePtr2;

    uniquePtr2 = std::move(uniquePtr1);

    // 输出:42
    std::cout << *uniquePtr2 << std::endl;

    return 0;
}

在上述示例中,我们通过使用std::move将uniquePtr1的所有权转移到uniquePtr2。这样,uniquePtr2现在拥有原始资源,并且uniquePtr1不再拥有资源。

使用自定义删除器

可以通过提供自定义删除器来指定std::unique_ptr在释放资源时的行为。删除器是一个函数对象或函数指针,用于定义资源释放的方式。
#include <iostream>
#include <memory>

struct CustomDeleter {
    void operator()(int* ptr) {
        std::cout << "Deleting resource: " << *ptr << std::endl;
        delete ptr;
    }
};

int main() {
    std::unique_ptr<int, CustomDeleter> uniquePtr(new int(42));

    // 输出:42
    std::cout << *uniquePtr << std::endl;

    return 0;
}

在上述示例中,我们创建了一个带有自定义删除器CustomDeleter的std::unique_ptr对象uniquePtr。当uniquePtr被销毁时,自定义删除器将被调用,并负责释放资源。

std::unique_ptr提供了一种轻量级的智能指针,适用于管理单个所有权的对象,提供了高效的内存管理和安全的资源释放。

关于array

C++删除array需要使用delete[],由于C++无法区分pointer指向的是单个对象还是array,因此指针自动删除会出错,标准库对此提供了特殊版本。
在C++11中,引入了std::unique_ptr的数组版本,即std::unique_ptr<T[]>,用于管理动态分配的数组对象。

下面是std::unique_ptr管理动态数组的示例:

#include <iostream>
#include <memory>

int main() {
    std::unique_ptr<int[]> uniquePtr(new int[5]);

    for (int i = 0; i < 5; i++) {
        uniquePtr[i] = i + 1;
    }

    for (int i = 0; i < 5; i++) {
        std::cout << uniquePtr[i] << " ";
    }

    // 输出:1 2 3 4 5
    std::cout << std::endl;

    return 0;
}

在上述示例中,我们使用std::unique_ptr<int[]>创建了一个std::unique_ptr对象uniquePtr来管理一个包含5个整数的动态数组。通过使用数组下标运算符[],我们可以访问和修改数组中的元素。当uniquePtr被销毁时,它会自动释放动态数组所占用的内存。

需要注意的是,std::unique_ptr<T[]>只适用于管理通过new T[]动态分配的数组,而不是指向已存在的数组,这个版本不提供操作符’*‘和’->'。在使用std::unique_ptr<T[]>时,不需要手动调用delete[]释放内存,std::unique_ptr会自动处理内存的释放。另外,这一版本不支持不同类型直接的转换,不允许指向派生元素类型。

其他操作

在这里插入图片描述

auto_ptr

std::auto_ptr是C++98标准引入的智能指针,用于管理动态分配的对象。然而,自从C++11起,std::auto_ptr已经被废弃,不推荐在新代码中使用,因为它存在一些缺陷和不安全的行为。
以下是一些关于std::auto_ptr的重要注意事项:

所有权的转移

与std::unique_ptr不同,std::auto_ptr支持所有权的转移,即可以将资源的所有权从一个std::auto_ptr转移到另一个std::auto_ptr。这意味着在转移所有权后,原始的std::auto_ptr将不再拥有资源。

不支持数组

std::auto_ptr只适用于管理单个对象,而不支持管理动态分配的数组。

删除器的限制

std::auto_ptr只支持使用默认的删除器,无法自定义删除器。这意味着在销毁std::auto_ptr时,只会调用delete来释放资源。

不安全的拷贝语义

std::auto_ptr的拷贝语义存在问题,它使用的是移动语义而不是传统的拷贝语义。这导致在拷贝后,原始的std::auto_ptr会失去对资源的所有权,可能导致资源的重复释放。

因此,建议使用C++11引入的更安全和更强大的智能指针类型,如std::unique_ptr用于独占所有权的情况,std::shared_ptr用于共享所有权的情况,以及std::weak_ptr用于解决循环引用问题。这些智能指针类型提供了更好的语义和更强的类型检查,能够更好地管理资源并提供更好的内存安全性。

补充

内存开销

相比于裸指针,智能指针通常会引入一定的内存开销。智能指针对象通常包含引用计数等额外的数据成员,这可能会占用更多的内存。虽然这个开销在大多数情况下可以忽略不计,但对于资源非常有限的嵌入式系统等特殊环境下,需要仔细考虑智能指针的使用。

不适合某些情况

智能指针并不是适用于所有情况的通用解决方案。在某些特定的应用场景下,例如与C接口进行交互、处理外部资源等,可能需要手动管理资源,而不适合使用智能指针。

语义差异和注意事项

不同类型的智能指针有不同的语义和行为,需要理解和注意其使用方式。例如,std::shared_ptr的共享所有权可能带来额外的开销和线程安全的问题,而std::unique_ptr则适用于独占所有权的场景。此外,智能指针的使用还需要注意循环引用、空指针检查、潜在的性能影响等问题。

虽然智能指针有其缺陷和注意事项,但它们在大多数情况下提供了方便、安全和可靠的资源管理方式。使用智能指针时,需要理解其语义和行为,并结合具体的应用场景进行选择和使用。

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

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

相关文章

ElasticSearch完整入门及springboot集成

目录 ElasticSearch概述ElasticSearch版本特性Elasticsearch 5Elasticsearch 6.0Elasticsearch 7.0Elasticsearch 8.0 ElasticSearch安装Windowslinux Kibana安装Windowslinux使用 IK分词器(elasticsearch插件)安装自定义的词典 ES的基本使用字段数据类型索引操作文档操作创建文…

什么是oa系统,什么是工单系统,有啥区别?

什么是oa系统&#xff0c;什么是工单系统&#xff0c;有啥区别&#xff1f; 一、OA系统与工单系统介绍 1、什么是OA系统 OA系统全称为Office Automation&#xff0c;即办公自动化系统。它是一种专门为企业和机构的日常办公工作提供服务的综合性软件平台&#xff0c;具有信息…

apple pencil有买的必要吗?平板电容笔推荐平价

在当今时代&#xff0c;高科技已经成为推动电子产品发展的重要动力之一。无论是在工作上&#xff0c;还是在学习上&#xff0c;iPad平板的使用都很方便。iPad将会和我们的生活联系在一起&#xff0c;不管是现在还是未来。iPad配上一个简单的电容笔&#xff0c;不仅可以提高工作…

分享11个常用的VSCode快捷键,让你编码更高效

因为频繁切换到鼠标可能会对你的手腕造成不利影响。 说实话&#xff0c;快速编程是我继续编码的原因之一&#xff08;开个玩笑&#xff0c;除非...&#xff09;。无论如何&#xff0c;我发现让我变得更快的关键是与鼠标分离。想一想&#xff0c;每次你需要移动鼠标时&#xff0…

STM32单片机(六)TIM定时器 -> 第四节:TIM输出比较练习(PWM驱动LED呼吸灯、PWM驱动舵机以及PWM驱动直流电机)

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

CSS查缺补漏之如何优雅解决margin垂直方向塌陷与合并问题?

一&#xff1a;父子元素之间margin垂直方向塌陷问题 在处理margin垂直方向问题时&#xff0c;经常会遇到在给子元素设置margin时&#xff0c;导致效果出现在了父元素上&#xff1b;如下代码所示&#xff1a; 代码原义是想实现三方面&#xff1a; ① 将box1的margin-top调为5…

从实现到原理,总结11种延迟任务的实现方式(上)

1 前言 延迟任务在我们日常生活中比较常见&#xff0c;比如订单支付超时取消订单功能&#xff0c;又比如自动确定收货的功能等等。 所以本篇文章就来从实现到原理来盘点延迟任务的11种实现方式&#xff0c;这些方式并没有绝对的好坏之分&#xff0c;只是适用场景的不大相同。…

高频前端React面试题汇总

近期整理了一下高频的前端面试题&#xff0c;分享给大家一起来学习。如有问题&#xff0c;欢迎指正&#xff01; 一、组件基础 1. React 事件机制 <div onClick{this.handleClick.bind(this)}>点我</div>React并不是将click事件绑定到了div的真实DOM上&#xff0…

ChatGPT+Mermaid自然语言流程图形化产出小试 | 京东云技术团队

ChatGPTMermaid语言实现技术概念可视化 本文旨在介绍如何使用ChatGPT和Mermaid语言生成流程图的技术。在现代软件开发中&#xff0c;流程图是一种重要的工具&#xff0c;用于可视化和呈现各种流程和结构。结合ChatGPT的自然语言处理能力和Mermaid的简单语法&#xff0c;可以轻…

【北邮国院大三下】Intellectual Property Law 知识产权基础 Week3

北邮国院大三电商在读&#xff0c;随课程进行整理知识点。仅整理PPT和相关法条中相对重要的知识点&#xff0c;个人认为相对不重要的细小的知识点不列在其中。如有错误请指出。转载请注明出处&#xff0c;祝您学习愉快。 如需要pdf格式的文件请私信联系或微信联系 本Week的主…

供应链|多期库存系统中具有销售损失的最优联合补货和转运策略

封面图来源&#xff1a; https://www.pexels.com/photo/aerial-shot-of-cargo-ship-on-sea-3840441/ 作者&#xff1a;Hossein Abouee-Mehrizi, Oded Berman, Shrutivandana Sharma 引用&#xff1a;Abouee-Mehrizi, H., Berman, O., & Sharma, S. (2015). Optimal joint r…

马原第三章复习2.生产力和生产关系

目录 社会基本矛盾和运动规律 社会基本矛盾和运动规律 这两个问题是最重点 生产力和生产关系 经济基础和上层建筑 生产力和生产关系 生产力是生产的能力 生产力是人类在实践中形成的改造自然使其适应自然的能力 生产力包含两个重要的要素:三要素 劳动

年化收益 21%:lightGBM的WFA滚动训练,使用qlib的alpha158因子集

原创文章第242篇&#xff0c;专注“个人成长与财富自由、世界运作的逻辑与投资"。 开始之前&#xff0c;先说说感受。 把整个框架与思路都在社群里开源出来&#xff0c;就是希望大家看懂思路&#xff0c;而不是拿一两个策略。说实话&#xff0c;投资哪有这种高确定性的“…

通义听悟上线,强大的视频会议和学习直播分析能力,人工智能如何改变我们的生活和工作方式?

什么是通义听悟 通义听悟已开启公测&#xff0c;公测期&#xff08;2023年6月1日至30日&#xff09;用户可体验所有AI功能&#xff0c;含全文概要、章节速览、发言总结等高阶AI功能&#xff0c;通过阿里云主账号登录。 官方给的应用场景&#xff1a; 1、实时会议记录&#x…

4.MySQL表的增删改查(进阶)

文章目录 &#x1f36f;1. 数据库约束&#x1f36f;&#x1f34e;1.1 约束类型&#x1f34e;&#x1f34f;1.2 NULL约束&#x1f34f;&#x1f34a;1.3 UNIQUE&#xff1a;唯一约束&#x1f34a;&#x1f34b;1.4 DEFAULT&#xff1a;默认值约束&#x1f34b;&#x1f352;1.5 …

MySQL数据库语言三、DCL语句

&#x1f618;作者简介&#xff1a;正在努力的99年公司职员。 &#x1f44a;宣言&#xff1a;人生就是B&#xff08;birth&#xff09;和D&#xff08;death&#xff09;之间的C&#xff08;choise&#xff09;&#xff0c;做好每一个选择。 &#x1f64f;创作不易&#xff0c;…

绩效管理的本质是激发员工,而不是扣工资!

绩效管理是企业管理中非常重要的一个环节&#xff0c;通过对员工表现进行评估和奖励&#xff0c;可以提高整个团队的士气和生产力。 然而&#xff0c;在实际操作中&#xff0c;有些企业却将绩效管理变成了惩罚员工的手段&#xff0c;甚至使用绩效扣除员工的薪水。这种做法不仅…

VALSE 2023:版面分析技术如何赋能生产生活?

目录 0 写在前面1 文档版面分析2 版面元素检测3 文档排版引擎总结 0 写在前面 VALSE年度研讨会旨在为中国青年学者在计算机视觉、图像处理、模式识别与机器学习研究领域提供一个具有深度的学术交流平台。VALSE秉持理性批判、勇于探索、实证和创新等科学精神&#xff0c;倡导自…

光伏电池建模及温度光照的影响曲线

光伏电池建模及温度光照的影响MATLAB程序及仿真资源-CSDN文库https://download.csdn.net/download/weixin_56691527/87910193模型介绍&#xff1a; 需要MATLAB2018B及以上的版本&#xff01;&#xff01; 首先根据根据环境修正公式搭建光伏电池仿真模型&#xff1a; 温度变化…

传统机器学习算法解析(opencv实现)

前言 文本主要解析在传统机器学习当中一些小的算法与思想&#xff0c;只是传统机器学习算法当中的一小部分&#xff0c;更多传统机器学习算法可参考我的另外几篇博客 链接1: PCA主成分分析 链接2: Canny边缘检测算法 链接3: K-Means聚类算法 链接4: SIFT算法分析 1. opencv …