当前位置: 首页 > news >正文

罗剑锋的C++实战笔记学习(一):const、智能指针、lambda表达式

1、const

1)、常量

const一般的用法就是修饰变量、引用、指针,修饰之后它们就变成了常量,需要注意的是const并未区分出编译期常量和运行期常量,并且const只保证了运行时不直接被修改

一般的情况,const放在左边,表示常量:

const int x = 100; // 常量
const int& rx = x; // 常量引用
const int* px = &x; // 常量指针

给变量加上const之后变量就成了常量,只能读、禁止写,编译器会帮你检查出所有对它的写操作,发出警告,在编译阶段防止有意或者无意的修改。这样一来,const常量用起来就相对安全一点。所以在设计函数的时候,将参数用const修饰的话,一个是可以保证效率,另一个是保证安全

2)、修饰成员函数

除此之外,const还能声明在成员函数上,const被放在了函数的后面,表示这个函数是一个常量,函数的执行过程是const的,不会修改对象的状态(即成员变量),比如:

class DemoClass final {
private:const long MAX_SIZE = 256; // const成员变量int m_value; // 成员变量
public:int get_value() const // const成员函数{// error: Cannot assign to non-static data member within const member function 'get_value'm_value = 100;return m_value;}
};
3)、指针常量

const放在*的右边,表示指针是常量(const pointer to int),指针不能被修改,而指向的变量可以被修改:

    int x = 100;int b = 150;int *const px = &x;*px = 102; // successpx = &b; // error: Cannot assign to variable 'px' with const-qualified type 'int *const'

int *const pxconst int* px的区别:

  • int *const px定义了一个指针常量,指针本身的地址不可改变,但可以改变指针所指向的数据
  • const int* px定义了一个指向常量的指针,可以改变指针的地址使其指向其他int,但不能通过此指针修改所指向的int值
4)、小结
const非const
对象(实例)const T:对象只读,只能调用const成员函数可以修改对象,调用任意成员函数
引用const T&:引用的对象只读,只能调用const成员函数
指针*const:指针指向的对象只读,只能调用const成员函数
成员函数func() const:不允许修改成员变量可以修改成员变量
指针常量const T*:表示指针是常量,指针不能被修改,而其指向的变量可以被修改指针和其指向的变量都可以被修改

2、智能指针

1)、unique_ptr

unique_ptr是一种独占资源所有权的指针,它会自动管理初始化时的指针,在离开作用域时析构释放内存

#include <iostream>
#include <memory>int main() {std::unique_ptr<int> ptr1(new int(10)); // int智能指针assert(*ptr1 == 10); // 使用*取内容assert(ptr1 != nullptr); // 判断是否为空指针std::unique_ptr<std::string> ptr2(new std::string("hello")); // string智能指针assert(*ptr2 == "hello"); // 使用*取内容assert(ptr2->size() == 5); // 使用->调用成员函数return 0;
}

在C++14的时候新加入了make_unique()函数,可以利用它构造一个unique_ptr对象:

#include <iostream>
#include <memory>int main() {auto ptr1 = std::make_unique<int>(42); // 工厂函数创建智能指针assert(ptr1 && *ptr1 == 42);auto ptr2 = std::make_unique<std::string>("god of war"); // 工厂函数创建智能指针assert(!ptr2->empty());return 0;
}

unique_ptr的所有权:

unique_ptr表示指针的所有权是唯一的,不允许共享,任何时候只能有一个人持有它

为了实现这个目的,unique_ptr应用了C++的转移(move)语义,同时禁止了拷贝赋值,所以,在向另一个unique_ptr赋值的时候,要特别留意,必须用std::move()函数显式地声明所有权转移

赋值操作之后,指针的所有权就被转走了,原来的unique_ptr变成了空指针,新的unique_ptr接替了管理权,保证所有权的唯一性:

#include <iostream>
#include <memory>int main() {auto ptr1 = std::make_unique<int>(42); // 工厂函数创建智能指针assert(ptr1 && *ptr1 == 42); // 此时智能指针有效auto ptr2 = std::move(ptr1); // 使用move()转移所有权assert(!ptr1 && ptr2); // ptr1变成了空指针return 0;
}

unique_ptr作为参数和返回值:

unique_ptr作为参数传递不会发生拷贝,但是会将对象所有权会转移到函数里,如下ptr会在main()方法结束之前被销毁:

#include <iostream>
#include <memory>class Resource {
public:Resource() { std::cout << "Resource acquired\n"; }~Resource() { std::cout << "Resource destroyed\n"; }friend std::ostream &operator<<(std::ostream &out, const Resource &res) {out << "I am a resource";return out;}
};void takeOwnership(std::unique_ptr<Resource> res) {if (res) {std::cout << *res << '\n';}
} // Resource对象会在这里销毁int main() {auto ptr{std::make_unique<Resource>()};// takeOwnership(ptr); // 不能这样写,unique_ptr禁止了拷贝赋值,需要使用std::move()函数显式地声明所有权转移takeOwnership(std::move(ptr));std::cout << "Ending program\n";return 0;
}

输出:

Resource acquired
I am a resource
Resource destroyed
Ending program

有时候不想对象的所有权转移到函数里,这时候可以通过get()方法获取对象,如下:

#include <iostream>
#include <memory>class Resource {
public:Resource() { std::cout << "Resource acquired\n"; }~Resource() { std::cout << "Resource destroyed\n"; }friend std::ostream &operator<<(std::ostream &out, const Resource &res) {out << "I am a resource";return out;}
};void takeOwnership(Resource *res) {if (res) {std::cout << *res << '\n';} else {std::cout << "No resource\n";}
}int main() {auto ptr{std::make_unique<Resource>()};takeOwnership(ptr.get());std::cout << "Ending program\n";return 0;
} // Resource对象会在这里销毁

输出:

Resource acquired
I am a resource
Ending program
Resource destroyed

unique_ptr可以直接作为返回值返回:

#include <iostream>
#include <memory>class Resource {
public:Resource() { std::cout << "Resource acquired\n"; }~Resource() { std::cout << "Resource destroyed\n"; }friend std::ostream &operator<<(std::ostream &out, const Resource &res) {out << "I am a resource";return out;}
};std::unique_ptr<Resource> createResource() {return std::make_unique<Resource>();
}int main() {auto ptr{createResource()};return 0;
}

在C++14及之前的版本中会使用std::move来返回Resource对象,在C++17及以后版本中进行了RVO优化(https://en.wikipedia.org/wiki/Copy_elision),尽管没有显式使用std::move,编译器依然能够识别并优化这个返回过程,直接将新创建的Resource对象的所有权从createResource函数内部转移到了main函数中的ptr变量,而无需实际执行移动构造函数

2)、shared_ptr

shared_ptr和unique_ptr不同是它的所有权是可以被安全共享的,也就是说支持拷贝赋值,允许被多个人同时持有,就像原始指针一样

在底层实现中,shared_ptr采用引用计数的方式实现。引用计数最开始的时候是1,表示只有一个持有者。如果发生拷贝赋值——也就是共享的时候,引用计数就增加(为了保证并发安全,引用计数器的加1,减1操作都是原子操作),而发生析构销毁的时候,引用计数就减少。只有当引用计数减少到0,也就是说,没有任何人使用这个指针的时候,它才会真正调用delete释放内存

#include <iostream>
#include <memory>class Resource {
public:Resource() { std::cout << "Resource acquired\n"; }~Resource() { std::cout << "Resource destroyed\n"; }
};int main() {auto ptr1 = std::make_shared<Resource>(); // 工厂函数创建智能指针assert(ptr1 && ptr1.unique()); // 此时智能指针有效且唯一{auto ptr2 = ptr1; // 直接拷贝赋值,不需要使用move()assert(ptr1 && ptr2); // 此时两个智能指针均有效assert(ptr1 == ptr2); // shared_ptr可以直接比较// 两个智能指针均不唯一,且引用计数为2assert(!ptr1.unique() && ptr1.use_count() == 2);assert(!ptr2.unique() && ptr2.use_count() == 2);std::cout << "Killing one shared pointer\n";} // ptr2离开了作用域,但是没有资源被销毁assert(ptr1 && ptr1.unique()); // 此时智能指针有效且唯一std::cout << "Killing another shared pointer\n";return 0;
} // ptr1离开了作用域,Resource对象会在这里销毁

输出:

Resource acquired
Killing one shared pointer
Killing another shared pointer
Resource destroyed

在上面的例子中, ptr2在自己的作用域中被创建,然后出了作用域后ptr2虽然被销毁,但是所管理的资源却在main方法结束后才被销毁

enable_shared_from_this:

如果不小心直接在类里面返回this对象想要获得该对象的shared_ptr,那么会让一个对象被delete两次,如下:

#include <iostream>
#include <memory>class Resource {
public:Resource() { std::cout << "Resource acquired\n"; }~Resource() { std::cout << "Resource destroyed\n"; }std::shared_ptr<Resource> GetSPtr() {return std::shared_ptr<Resource>(this);}
};int main() {auto sptr1 = std::make_shared<Resource>();auto sptr2 = sptr1->GetSPtr();return 0;
}

输出:

Resource acquired
Resource destroyed
studyProject(6959,0x7ff854f04700) malloc: *** error for object 0x6000035ed1f8: pointer being freed was not allocated
studyProject(6959,0x7ff854f04700) malloc: *** set a breakpoint in malloc_error_break to debug

上面的代码其实会生成两个独立的shared_ptr,他们的控制块是独立的,所以导致Resource被释放了两次

使用enable_shared_from_this可以避免上述情况:

#include <iostream>
#include <memory>class Resource : public std::enable_shared_from_this<Resource> {
public:Resource() { std::cout << "Resource acquired\n"; }~Resource() { std::cout << "Resource destroyed\n"; }std::shared_ptr<Resource> GetSPtr() {return shared_from_this();}
};int main() {auto sptr1 = std::make_shared<Resource>();auto sptr2 = sptr1->GetSPtr();return 0;
}

shared_ptr的循环引用问题:

shared_ptr的引用计数也导致了一个新的问题,就是循环引用,这在把shared_ptr作为类成员的时候最容易出现,典型的例子就是链表节点

#include <iostream>
#include <memory>class Node {
public:using this_type = Node;using shared_type = std::shared_ptr<this_type>;Node(const std::string &name) : name(name) {std::cout << name << " created\n";}~Node() {std::cout << name << " destroyed\n";}std::string name;shared_type next; // 使用智能指针来指向下一个节点
};int main() {auto n1 = std::make_shared<Node>("n1");auto n2 = std::make_shared<Node>("n2");assert(n1.use_count() == 1); // 引用计数为1assert(n2.use_count() == 1);n1->next = n2; // 两个节点互指,形成了循环引用n2->next = n1;assert(n1.use_count() == 2); // 引用计数为2assert(n2.use_count() == 2); // 无法减到0,无法销毁,导致内存泄漏return 0;
}

输出:

n1 created
n2 created

上面的代码中,两个节点指针刚创建时,引用计数是1,但指针互指(即拷贝赋值)之后,引用计数都变成了2

这个时候,shared_ptr意识不到这是一个循环引用,多算了一次计数,后果就是引用计数无法减到0,无法调用析构函数执行delete,最终导致内存泄漏

3)、weak_ptr

weak_ptr是专门为打破循环引用而设计,它实际上不会托管对象,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。在需要的时候,可以调用weak_ptr的成员函数lock(),获取shared_ptr(强引用)

#include <iostream>
#include <memory>class Node {
public:using this_type = Node;using shared_type = std::weak_ptr<this_type>; // 注意这里,别名改用weak_ptrNode(const std::string &name) : name(name) {std::cout << name << " created\n";}~Node() {std::cout << name << " destroyed\n";}std::string name;shared_type next;
};int main() {auto n1 = std::make_shared<Node>("n1");auto n2 = std::make_shared<Node>("n2");n1->next = n2; // 两个节点互指,形成了循环引用n2->next = n1;assert(n1.use_count() == 1); // 因为使用了weak_ptr,引用计数为1assert(n2.use_count() == 1); // 打破循环引用,不会导致内存泄漏if (!n1->next.expired()) { // 检查指针是否有效auto ptr = n1->next.lock(); // lock()获取shared_ptrassert(ptr == n2);}return 0;
}

输出:

n1 created
n2 created
n2 destroyed
n1 destroyed
4)、小结

unique_ptr是一种独占资源所有权的指针,它会在栈上分配,然后在离开作用域之后进行释放,删除里面持有的对象,它只能使用move语义转移对象。所以如果你想操作一个指针,在进入作用域的时候分配好内存,然后在离开作用域的时候安全释放对象,那么可以使用它

shared_ptr所管理的资源可以被多个对象持有,并且使用引用计数策略来释放对象,如果计数没有清零,那么它所管理的资源不会释放

weak_ptr不管理对象,只是shared_ptr对象管理的资源的观察者,所以它不影响共享资源的生命周期,它用于解决shared_ptr循环引用

3、lambda表达式

1)、lambda基本使用
#include <iostream>int main() {auto func = [](int x) // 定义一个lambda表达式{std::cout << x * x << std::endl; // lambda表达式的具体内容};func(3); // 调用lambda表达式return 0;
}

C++里的lambda表达式除了可以像普通函数那样被调用,还有一个普通函数所不具备的特殊本领,就是可以捕获外部变量,在内部的代码里直接操作

#include <iostream>int main() {int n = 10; // 一个外部变量auto func = [=](int x) // lambda表达式,用=捕获{std::cout << x * n << std::endl; // 直接操作外部变量};func(3); // 调用lambda表达式return 0;
}
2)、使用lambda的注意事项

1)lambda的形式

嵌套定义lambda表达式

#include <iostream>int main() {auto f1 = []() // 定义一个lambda表达式{std::cout << "lambda f1" << std::endl;auto f2 = [](int x) // 嵌套定义lambda表达式{return x * x;}; // lambda f2std::cout << f2(10) << std::endl;}; // lambda f1f1();return 0;
}

匿名lambda表达式

#include <iostream>int main() {std::vector<int> v = {3, 1, 8, 5, 0}; // 标准容器std::cout << *find_if(begin(v), end(v), // 标准库里的查找算法[](int x) // 匿名lambda表达式,不需要auto赋值{return x >= 5; // 用做算法的谓词判断条件})<< std::endl; // 语句执行完,lambda表达式就不存在了return 0;
}

2)lambda的变量捕获

lambda的变量捕获要点:

  • [=]:表示按值捕获所有外部变量,表达式内部是值的拷贝,并且不能修改
  • [&]:按引用捕获所有外部变量,内部以引用的方式使用,可以修改
  • 可以在[]里明确写出外部变量名,指定按值或者按引用捕获
int main() {int x = 33; // 一个外部变量auto f1 = [=]() // lambda表达式,用=按值捕获{//x += 10; // x只读,不允许修改};auto f2 = [&]() // lambda表达式,用&按引用捕获{x += 10; // x是引用,可以修改};auto f3 = [=, &x]() // lambda表达式,用&按引用捕获x,其他的按值捕获{x += 20; // x是引用,可以修改};return 0;
}

3)泛型的lambda

在C++14里,lambda表达式可以实现泛型化,相当于简化了的模板函数

#include <iostream>int main() {auto f = [](const auto &x) // 参数使用auto声明,泛型化{return x + x;};std::cout << f(3) << std::endl; // 参数类型是intstd::cout << f(0.618) << std::endl; // 参数类型是doublestd::string str = "matrix";std::cout << f(str) << std::endl; // 参数类型是stringreturn 0;
}
3)、小结
  1. lambda表达式是一个闭包,能够像函数一样被调用,像变量一样被传递
  2. 可以使用auto自动推导类型存储lambda表达式,但C++鼓励尽量就地匿名使用,缩小作用域
  3. lambda表达式使用[=]的方式按值捕获,使用[&]的方式按引用捕获,空的[]则是无捕获(也就相当于普通函数)
  4. 捕获引用时必须要注意外部变量的生命周期,防止变量失效
  5. C++14里可以使用泛型的lambda表达式,相当于简化的模板函数

参考:

07 | const/volatile/mutable:常量/变量究竟是怎么回事?

C++ 中让人头晕的const & constexpr

08 | smart_ptr:智能指针到底“智能”在哪里?

写给[C++ ]新人智能指针避坑指南

10 | lambda:函数式编程带来了什么?

相关文章:

罗剑锋的C++实战笔记学习(一):const、智能指针、lambda表达式

1、const 1&#xff09;、常量 const一般的用法就是修饰变量、引用、指针&#xff0c;修饰之后它们就变成了常量&#xff0c;需要注意的是const并未区分出编译期常量和运行期常量&#xff0c;并且const只保证了运行时不直接被修改 一般的情况&#xff0c;const放在左边&…...

宁德时代天行发布,商用车超充时代来临

近日&#xff0c;宁德时代正式推出商用动力电池品牌——“宁德时代天行”&#xff0c;同时发布“宁德时代天行轻型商用车&#xff08;L&#xff09;-超充版”和“宁德时代天行轻型商用车&#xff08;L&#xff09;-长续航版”两款产品&#xff0c;可实现4C超充能力和500km的实况…...

硅纪元应用评测 | 弱智吧大战GPT4o和Claude 3.5 Sonnet

"硅纪元AI应用测评"栏目&#xff0c;深入解析和评测最新的人工智能应用&#xff0c;提供专业见解和实用建议。不论您是AI专家还是科技爱好者&#xff0c;都能找到权威、详尽的测评&#xff0c;帮助您在快速发展的AI领域中做出最佳选择。一起探索AI的真实潜力&#xf…...

注意力机制 attention Transformer 笔记

动手学深度学习 这里写自定义目录标题 注意力加性注意力缩放点积注意力多头注意力自注意力Transformer 注意力 注意力汇聚的输出为值的加权和 查询的长度为q&#xff0c;键的长度为k&#xff0c;值的长度为v。 q ∈ 1 q , k ∈ 1 k , v ∈ R 1 v {\bf{q}} \in {^{1 \times…...

开始尝试从0写一个项目--后端(二)

实现学生管理 新增学生 接口设计 请求路径&#xff1a;/admin/student 请求方法&#xff1a;POST 请求参数&#xff1a;请求头&#xff1a;Headers&#xff1a;"Content-Type": "application/json" 请求体&#xff1a;Body&#xff1a; id 学生id …...

【图解大数据技术】Hive、HBase

【图解大数据技术】Hive、HBase Hive数据仓库Hive的执行流程Hive架构数据导入Hive HBaseHBase简介HBase架构HBase的列式存储HBase建表流程HBase数据写入流程HBase数据读取流程 Hive Hive是基于Hadoop的一个数据仓库工具&#xff0c;Hive的数据存储在HDFS上&#xff0c;底层基于…...

composables 目录下的文件(web前端)

composables 目录通常用于存放可组合的函数或逻辑&#xff0c;这些函数或逻辑可以在不同的组件中复用。具体来说&#xff0c;composables 目录下的文件通常包含以下内容&#xff1a; 组合式函数 (Composable Functions)&#xff1a; 这些函数利用 Vue 3 的组合式 API&#xff0…...

使用Python绘制堆积柱形图

使用Python绘制堆积柱形图 堆积柱形图效果代码 堆积柱形图 堆积柱形图&#xff08;Stacked Bar Chart&#xff09;是一种数据可视化图表&#xff0c;用于显示不同类别的数值在某一变量上的累积情况。每一个柱状条显示多个子类别的数值&#xff0c;子类别的数值在柱状条上堆积在…...

DP:二维费用背包问题

文章目录 &#x1f3b5;二维费用背包问题&#x1f3b6;引言&#x1f3b6;问题定义&#x1f3b6;动态规划思想&#x1f3b6;状态定义和状态转移方程&#x1f3b6;初始条件和边界情况 &#x1f3b5;例题&#x1f3b6;1.一和零&#x1f3b6;2.盈利计划 &#x1f3b5;总结 &#x1…...

C语言标准库中的函数

由于C语言标准库中的函数非常多&#xff0c;我将按类别列出一些常见函数及其作用。请注意&#xff0c;这里不可能列出所有函数&#xff0c;但我会尽量覆盖主要的类别和函数。 ### 标准输入输出 - printf: 格式化输出到标准输出&#xff08;通常是屏幕&#xff09;。 - scanf: …...

Qt5.9.9 关于界面拖动导致QModbusRTU(QModbusTCP没有测试过)离线的问题

问题锁定 参考网友的思路&#xff1a; Qt5.9 Modbus request timeout 0x5异常解决 网友认为是Qt的bug&#xff0c; 我也认同&#xff1b;网友认为可以更新模块&#xff0c; 我也认同&#xff0c; 我也编译了Qt5.15.0的code并成功安装到Qt5.9.9中进行使用&#xff0c;界面拖…...

API的定义理解

前言 在程序员的日常工作中&#xff0c;“API”这个词在程序员的口中重复的次数&#xff0c;绝对是名列前茅的。 但是对刚开始工作的新人来说&#xff0c;API这个概念还是比较模糊。 确实&#xff0c;API这个概念是随着语义环境而不一样的&#xff0c;所以会让人迷惑。 下面…...

启航IT之旅:高考假期预习指南

标题&#xff1a;启航IT之旅&#xff1a;高考假期预习指南 随着高考的落幕&#xff0c;许多有志于IT领域的学子们即将踏上新的学习旅程。这个假期&#xff0c;是他们探索IT世界的黄金时期。本文将为准IT新生们提供一份全面的预习指南&#xff0c;帮助他们为未来的学习和职业生…...

HarmonyOS开发:循环渲染ForEach

需求&#xff1a; 创建多个列表组件&#xff0c;并实现点赞功能 语言&#xff1a; ArkTS 平台&#xff1a; DevEco Studio ForEach 接口描述 ForEach( arr: Array, itemGenerator: (item: Object, index: number) > void, keyGenerator?: (item: Object, index: number) &…...

构建工程化:多种不同的工程体系如何编写MakeFile

源码分析 核心MakeFile 这个 Makefile 是一个复杂的构建脚本&#xff0c;用于管理和构建一个大型项目。它包括多个目标、条件判断和递归调用 make 命令来处理多个子项目和子目录。让我们逐部分进行详细解析。 伪目标和变量定义 .PHONY: all clean install build test init.…...

聚焦从业人员疏散逃生避险意识能力提升,推动生产经营单位每年至少组织开展(疏散逃生演练,让全体从业人员熟知逃生通道、安全出口及应急处置要求,形成常态化机制。

聚焦从业人员疏散逃生避险意识能力提升&#xff0c;推动生产经营单位每年至少组织开展(疏散逃生演练&#xff0c;让全体从业人员熟知逃生通道、安全出口及应急处置要求&#xff0c;形成常态化机制。完整试题答案查看 A.三次B.两次C.一次 综合运用“四不两直”、明察暗访、 ()、…...

【手机取证】如何使用360加固助手给apk加固

文章关键词&#xff1a;手机取证、电子数据取证、数据恢复 一、前言 APP加固是对APP代码逻辑的一种保护。原理是将应用文件进行某种形式的转换&#xff0c;包括不限于隐藏&#xff0c;混淆&#xff0c;加密等操作&#xff0c;进一步保护软件的利益不受损坏&#xff0c;下面给…...

Vue的介绍

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…...

MySql数据库常用指令合集

MySql数据库常用指令合集 一、创建数据库db11.创建表 字段---表头 student_no,username,sex2.新增单条插入多条插入3.删除4.更新5.查询5.1.查询该表全部信息5.2.查询该表中username&#xff0c;并且要求名字为zhangsan性别女&#xff0c;还可以用&#xff08;or&#xff09; 6.…...

ArcGIS Pro SDK (七)编辑 13 注解

ArcGIS Pro SDK &#xff08;七&#xff09;编辑 13 注解 文章目录 ArcGIS Pro SDK &#xff08;七&#xff09;编辑 13 注解1 注释构建工具2 以编程方式启动编辑批注3 更新批注文本4 修改批注形状5 修改批注文本图形6 接地到网格 环境&#xff1a;Visual Studio 2022 .NET6 …...

模拟面试001-Java开发工程师+简历+问题+回答

模拟面试001-Java开发工程师简历问题回答 目录 模拟面试001-Java开发工程师简历问题回答面试简历面试官题问求职者回答1. 关于Java编程和技术栈2. 关于XX在线购物平台项目3. 关于XX企业资源规划系统项目4. 团队协作与项目管理5. 个人发展与职业规划 参考资料 面试简历 **个人信…...

微信小程序 ——入门介绍及简单的小程序编写

目录 一、小程序入门 1.1 什么是小程序 1.2 小程序的优点 1.3 小程序注册 1.4 安装开发工具 1.5 创建第一个小程序 二、小程序目录结构及入门案例 2.1 目录结构 2.2 入门案例 2.2.1 创建界面 2.2.2 设置标题 2.2.3 编写WXML文件 2.2.4 编写JS文件 2.2.5 编写WXSS…...

ubuntu20.04安装lio-sam

1、依赖功能包安装 sudo apt install ros-noetic-robot-state-publisher sudo apt-get install ros-noetic-robot-localization libmetis-dev 2、boost版本 boost版本查看&#xff1a;cat /usr/include/boost/version.hpp | grep "BOOST_LIB_VERSION" boost版本为1.…...

Kafka系列之Kafka知识超强总结

一、Kafka简介 Kafka是什么 Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff08;消息引擎系统&#xff09;&#xff0c;它可以处理消费者在网站中的所有动作流数据。 这种动作&#xff08;网页浏览&#xff0c; 搜索和其他用户的行动&#xff09;是在现代网络上的许多社…...

第32讲:K8S集群与Cephfs文件系统集成

文章目录 1.在K8S环境下RBD与Cephfs的使用对比2.Cephfs环境介绍3.在Ceph集群中为K8S创建单独Cephfs文件系统和认证用户3.1.创建一个K8S使用的Cephfs文件系统3.2.将创建的Cephfs文件系统挂载到本地路径3.3.创建K8S连接Ceph集群使用的认证用户 4.K8S PV存储卷使用Cephfs文件系统4…...

服务器数据恢复—DS5300存储raid5阵列数据恢复案例

服务器存储数据恢复环境&#xff1a; 某单位一台某品牌DS5300存储&#xff0c;1个机头4个扩展柜&#xff0c;50块硬盘组建2组RAID5磁盘阵列&#xff08;一组raid5阵列有27块成员盘&#xff0c;存放Oracle数据库文件&#xff1b;另外一组raid5阵列有23块成员盘&#xff09;。存储…...

使用Ubuntu 22.04安装Frappe-Bench【二】

系列文章目录 第一章 使用VMware创建Ubuntu 22.04【一】 文章目录 系列文章目录前言什么是Frappe-Bench&#xff1f;使用安装ERPNext能实现什么效果&#xff1f; 官网给了一个说明 一、使用Ubuntu 22.04安装Frappe-Bench一、安装要求二、安装命令三、 可能出现问题 总结 前言 …...

MySQL增删改查

1.创建数据库&#xff1a; 使用CREATE DATABASE语句 CREATE DATABASE school;show databases; 列出MySQL数据库管理系统的数据库列表 2.切换数据库&#xff1a; 使用USE语句选择要操作的数据库 USE school&#xff1b;select database (); 当前所在库mysql> select…...

Java跳出循环的四种方式

1、continue,break,return continue&#xff1a;跳出当前层循环的当前语句&#xff0c;执行当前层循环的下一条语句。   continue标签 break&#xff1a;跳出当前层循环。 break标签&#xff1a;多层循环时&#xff0c;跳到具体某层循环。 return&#xff1a;结束所有循环…...

直播预告|飞思实验室暑期公益培训7月10日正式开启,报名从速!

01 培训背景 很荣幸地向大家宣布&#xff1a;卓翼飞思实验室将于7月10日正式开启为期两个月的暑期公益培训&#xff01;本次培训为线上直播&#xff0c;由中南大学计算机学院特聘副教授&#xff0c;RflySim平台总研发负责人戴训华副教授主讲。 培训将基于“RflySim—智能无人…...

3-2 梯度与反向传播

3-2 梯度与反向传播 主目录点这里 梯度的含义 可以看到红色区域的变化率较大&#xff0c;梯度较大&#xff1b;绿色区域的变化率较小&#xff0c;梯度较小。 在二维情况下&#xff0c;梯度向量的方向指向函数增长最快的方向&#xff0c;而其大小表示增长的速率。 梯度的计算 …...

【qt】如何获取本机的IP地址?

需要用到这个类QHostInfo和pro里面添加network模块 用这个类的静态函数forName()来获取该主机名的信息 返回的就是这个类 这个QHostInfo类就包括主机的IP地址信息 用静态函数addresses()来获取 返回的是一个QHostAddress的容器 QList<QHostAddress>addrList hostIn…...

芯片的PPA-笔记

写在前面&#xff1a;这个仅记录自己对芯片PPA的一些思考&#xff0c;不一定正确&#xff0c;还请各位网友思辨的看待&#xff0c;欢迎大家谈谈自己的想法。 1 此次笔记的起因 记录的原因&#xff1a;自己在整理这段时间的功耗总结&#xff0c;又看到工艺对功耗的影响&#x…...

2024阿里巴巴全球数学竞赛决赛中的数列题解析(分析与方程方向第4题)

早点关注我&#xff0c;精彩不错过&#xff01; 上周给大家聊了一道有LLM背景的阿里数赛题&#xff0c;详情请戳&#xff1a; 2023阿里巴巴全球数学竞赛决赛中的LLM背景题解析&#xff08;应用与计算数学部分第2题&#xff09; 看起来大家还比较喜欢看这种具体问题求解和思路分…...

学java的第3天 后端商城小程序工作

1.数据库的大坑 特殊字段名 ’我的图片表中有一个字段是描述我写成desc了&#xff0c;正好是mysql中的关键字 就不能使用了 2.后端编写 2.1可以把请求分开 在商品浏览页中 只显示商品的大致信息 当用户再点击其他按钮时在发出请求 2.2把请求合并 把数据整合到一起 利用ass…...

DevOps实战:使用GitLab+Jenkins+Kubernetes(k8s)建立CI_CD解决方案

一.系统环境 本文主要基于Kubernetes1.21.9和Linux操作系统CentOS7.4。 服务器版本docker软件版本Kubernetes(k8s)集群版本CPU架构CentOS Linux release 7.4.1708 (Core)Docker version 20.10.12v1.21.9x86_64CI/CD解决方案架构图:CI/CD解决方案架构图描述:程序员写好代码之…...

Apache Seata配置管理原理解析

本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 Apache Seata配置管理原理解析 说到Seata中的配置管理&#xff0c;大家可能会想到Seata中适配…...

深入理解C# log4Net日志框架:功能、使用方法与性能优势

文章目录 1、log4Net的主要特性2、log4Net框架详解配置日志级别 3、log4Net的使用示例4、性能优化与对比5、总结与展望 在软件开发过程中&#xff0c;日志记录是一个不可或缺的功能。它可以帮助开发者追踪错误、监控应用程序性能&#xff0c;以及进行调试。在C#生态系统中&…...

BDD 100K dataset 的标签数据结构(json文件)

最近在筛选自己需要的labels&#xff0c;所以要弄清楚这个数据集的数据结构才行&#xff1a; 1.整个json文件以列表形式储存 2.每张图片以一个字典形式储存 3.存储图片的字典内的以‘name’为key的键值对对应的‘value’是我需要的图片名称信息 4.存储图片的字典内的以‘label…...

AcWing 1550:完全二叉搜索树

【题目来源】https://www.acwing.com/problem/content/1552/【题目描述】二叉搜索树 (BST) 递归定义为具有以下属性的二叉树&#xff1a; &#xff08;1&#xff09;若它的左子树不空&#xff0c;则左子树上所有结点的值均小于它的根结点的值 &#xff08;2&#xff09;若它的右…...

使用kali Linux启动盘轻松破解Windows电脑密码

破解分析文章仅限用于学习和研究目的&#xff1b;不得将上述内容用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。谢谢&#xff01;&#xff01; 效果展示&#xff1a; 使用kali Linux可以轻松破解Windows用户及密码 准备阶段&#xff1a; &#xff08…...

Vue2中跨组件共享公共属性的方法、优缺点与实现

一、vuex&#xff08;最常用&#xff09; 优缺点 优点&#xff1a;集中管理状态&#xff0c;组件间解耦&#xff0c;易于调试和测试。缺点&#xff1a;学习成本较高&#xff0c;对于小项目可能过于复杂。 适用场景 大型、复杂的单页面应用&#xff08;SPA&#xff09;。需要全局…...

2024亚太杯数学建模竞赛(B题)的全面解析

你是否在寻找数学建模比赛的突破点&#xff1f;数学建模进阶思路&#xff01; 作为经验丰富的数学建模团队&#xff0c;我们将为你带来2024亚太杯数学建模竞赛&#xff08;B题&#xff09;的全面解析。这个解决方案包不仅包括完整的代码实现&#xff0c;还有详尽的建模过程和解…...

【PWN · ret2syscall | GoPwn】[2024CISCN · 华中赛区]go_note

一道GoPwn&#xff0c;此外便是ret2syscall的利用。然而过程有不小的曲折&#xff0c;参考 返璞归真 师傅的wp&#xff0c;堪堪完成了复现。复现过程中&#xff0c;师傅也灰常热情回答我菜菜的疑问&#xff0c;感谢&#xff01;2024全国大学生信息安全竞赛&#xff08;ciscn&am…...

关于学习方法的优化

这是一种新的学习方法&#xff0c;一种新的学习形式&#xff0c;可以通过歌唱的方式&#xff0c;运用&#xff0c;把自己每天要进行的内容进行一个复习&#xff0c;进行一个重复&#xff0c;这样可以实现随时随地进行一个学习&#xff0c;这样可以帮助快速走出来&#xff01; 您…...

万界星空科技MES系统中的排版排产功能

在当今高度竞争的市场环境中&#xff0c;企业对于生产管理的效率和质量要求日益提高。作为智能制造的重要组成部分&#xff0c;制造执行系统&#xff08;MES&#xff09;以其强大的功能&#xff0c;在提升企业生产能力方面发挥着不可替代的作用。万界星空科技作为行业领先的智能…...

kubeadm离线部署kubernetesv1.30.0

背景&#xff1a;最近由于docker image获取镜像受限的问题&#xff0c;以及公司内部部署kubernetes受限于内部网络无法访问公网的问题&#xff0c;对于离线部署kubernetes成为不是十分方便。谨以此文仅供参考。 kubernetes部署节点信息 kubernetes版本 1.30.0 操作系统版本&a…...

【PYG】dataloader和densedataloader

DenseDataLoader 是专门用于处理稠密图数据的&#xff0c;而 DataLoader 通常用于处理稀疏图数据。两者的主要区别在于它们的输入数据格式和处理方式。DenseDataLoader 适合处理固定大小的邻接矩阵和节点特征矩阵的数据&#xff0c;而 DataLoader 更加灵活&#xff0c;可以处理…...

完美解决ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: NO)

已解决ERROR 1045 (28000): Access denied for user ‘root‘‘localhost‘ (using password: NO) 下滑查看解决方法 文章目录 报错问题解决思路解决方法交流 报错问题 ERROR 1045 (28000): Access denied for user ‘root‘‘localhost‘ (using password: NO) 解决思路 对…...

ForkJoinPool 简介

引言 在现代并行编程中&#xff0c;处理大规模任务时将任务分割成更小的子任务并行执行是一种常见的策略。Java 提供了 Fork/Join 框架来支持这一模式&#xff0c;其中 ForkJoinPool 是其核心组件。本文将详细介绍 ForkJoinPool 的概念、使用方法和实际应用。 1. ForkJoinPoo…...