通过文字图像——代码图形注释自动生成

举报
梦笔生花 发表于 2024/10/27 23:53:25 2024/10/27
【摘要】 大家在学(CTRL)习(C)别人代码的时候,看到别人的代码程序,在日志中有很多很酷的代码注释,或者是有一些图形化注释方便理解。之前本人以为都是一个个手敲出来的。然后在网上一番搜索,找到了很多神奇的好网站,以用于图形注释生成。 代码图形注释自动生成技术是一种将代码逻辑和结构可视化的创新工具。它通过解析编程代码,并将代码的功能、结构和逻辑关系转换成直观的图形注释,从而使得程序员能够更加轻松地理解和分

多线程的创建创建线程比较简单,C++提供头文件thread,使用std的thread实例化一个线程对象创建。

std::thread 在 #include 头文件中声明,因此使用 std::thread 时需要包含 #include 头文件。

#include <iostream>

#include <thread>

#include <stdlib.h> //sleep


using namespace std;


void t1() //普通的函数,用来执行线程

{

for (int i = 0; i < 10; ++i)

{

cout << "t1111\n";

sleep(1);

}

}

void t2()

{

for (int i = 0; i < 20; ++i)

{

cout << "t22222\n";

sleep(1);

}

}

int main()

{

thread th1(t1); //实例化一个线程对象th1,使用函数t1构造,然后该线程就开始执行了(t1())

thread th2(t2);


th1.join(); // 必须将线程join或者detach 等待子线程结束主进程才可以退出

th2.join();


cout << "here is main\n\n";


return 0;

}

LIO-SAM中的线程操作

int main(int argc, char** argv)

{

ros::init(argc, argv, "lio_sam");


mapOptimization MO;


ROS_INFO("\033[1;32m----> Map Optimization Started.\033[0m");


std::thread loopthread(&mapOptimization::loopClosureThread, &MO);

std::thread visualizeMapThread(&mapOptimization::visualizeGlobalMapThread, &MO);


ros::spin();


loopthread.join();

visualizeMapThread.join();


return 0;

}

两个线程主要运行的函数主要时回环检测线程和全局地图可视化线程,在每个线程内部都有互斥锁操作防止两个线程运行时对相同数据进行干扰

互斥锁mutex是用来保证线程同步的,防止不同的线程同时操作同一个共享数据

通过mutex可以方便的对临界区域加锁,std::mutex类定义于mutex头文件,是用于保护共享数据避免从多个线程同时访问的同步原语。它提供了lock,try_lock,unlock等几个接口

#include<iostream>

#include<thread>

#include<mutex>


using namespace std;


mutex m;

int cnt = 10;


void thread1() {

while (cnt > 5){

m.lock();

if (cnt > 0) {

--cnt;

cout << cnt << endl;

}

m.unlock();

}

}


void thread2() {

while (cnt > 0) {

m.lock();

if (cnt > 0) {

cnt -= 10;

cout << cnt << endl;

}

m.unlock();

}

}


int main(int argc, char* argv[]) {

thread th1(thread1); //实例化一个线程对象th1,该线程开始执行

thread th2(thread2);

th1.join();

th2.join();

cout << "main..." << endl;

return 0;

}

aloam中互斥锁的应用

void laserCloudCornerLastHandler(const sensor_msgs::PointCloud2ConstPtr &laserCloudCornerLast2)

{

    mBuf.lock();

    cornerLastBuf.push(laserCloudCornerLast2);

    mBuf.unlock();

}

在接收laserCloudCornerLast2时为了完整的接收到当前帧角点点云信息在开始接受时为了防止其他线程影响该数据使用mBuf.lock();接受完后再打开mBuf.unlock();

std::lock_guard因为mutex需要在数据处理开始和结束时成对出现,当数据处理过程很长时容易遗忘造成危害,所以使用std::lock_guard

要加锁的代码段,我们用{}括起来形成一个作用域,括号的开端创建lock_guard对象,把mutex对象作为参数传入lock_guard的构造函数即可

这就相当于下面代码

std::thread thread2([&]()){

for(int i=0;i<10000;i++)

{

mtx.lock();

++num;

mtx.unlock();

}

});

LIO-SAM中的std::lock_guard

//订阅imu里程计,由imuPreintegration积分计算得到的每时刻imu位姿

void odometryHandler(const nav_msgs::Odometry::ConstPtr& odometryMsg)

{

std::lock_guard<std::mutex> lock2(odoLock);

odomQueue.push_back(*odometryMsg);

}

在接收里程计数据时防止其他线程对接受数据造成干扰,使用std::lock_guard。该对象只在他所处的大括号内起作用

顺序容器概述

顺序容器使用原则通常,使用vector是最好的选择,除非你有很好的理由选择其他容器

Vector由于一般情况下vector使用较多,首先介绍一些vector的使用

size()返回容器中元素数目;

swap()交换两个容器的内容;

begin()返回一个指向容器中第一个元素的迭代器;

end()返回一个表示超过容器尾的迭代器(指向容器最后一个元素后面的那个元素位置);

push_back()将元素添加到矢量(vector)末尾;

erase()删除矢量中给定区间的元素;

insert()插入指定区间的元素到指定位置;

deque在slam接收储存一些传感器数据时也是用到队列先进先出

deque是一个的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector 容器也可以在头尾两端插入元素,但是在其头部操作效率奇差,无法被接受。

用sort对deque排序

#include <iostream>

#include <deque>

#include <algorithm>

using namespace std;


void printDeque(const deque<int> &d)

{

for(deque<int>::const_iterator it = d.begin(); it != d.end(); it++)

{

cout<<*it<<" ";        

}

cout<<endl;

}


/* 回调函数 */

bool compare(int v1, int v2)

{

return v1 > v2; /* 此时的排序是从大到小 */

/* 如果从小到大应该改为"v1 < v2" */

}


void test()

{

deque<int> d;

d.push_back(3);

d.push_back(4);

d.push_back(1);

d.push_back(7);

d.push_back(2);


sort(d.begin(), d.end(), compare);

printDeque(d);

}

assign()STL中不同容器之间是不能直接赋值的,assign()可以实现不同容器但相容的类型赋值,如:

list<string> names;

vector<const char*> oldstyle = { "I","love","you" };

//names = oldstyle;错误!不同的类型不能执行"="操作

names.assign(oldstyle.cbegin(), oldstyle.cend());

list<string>::iterator it;

for (auto it = names.begin(); names.begin() != names.end(); it++)

cout << *it << " ";

在 lego-loam中有如下操作

segMsg.startRingIndex.assign(N_SCAN, 0);

segMsg.endRingIndex.assign(N_SCAN, 0);

智能指针概念以及为什么引入智能指针

shared_ptr类的创建

shared_ptr<string> p1 //shared_ptr 指向string类型

shared_ptr<list<int>> p2 //shared_ptr 指向int类型的list

make_shared函数使用最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数。此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。当要用make_shared时,必须指定想要创建的对象的类型,定义方式与模板类相同。在函数名之后跟一个尖括号,在其中给出类型。例如,调用make_shared<string>时传递的参数必须与string的某个构造函数相匹配。如果不传递任何参数,对象就会进行值初始化。

//指向一个值为24的int的shared_ptr

shared_ptr&lt;int&gt; p3 =make_shared&lt;int&gt;(42)

//指向一个值为"99999"的string的shared_ptr

shared_ptr&lt;int&gt; p4 =make_shared&lt;string&gt;(5,'9')

//指向一个值为0的int的shared_ptr

shared_ptr&lt;int&gt; p3 =make_shared&lt;int&gt;()

auto和make_shared通常用auto定义一个对象来保存make_shared的结果

//指向一个值为24的int的shared_ptr

auto p6 =make_shared&lt;int&gt;(42)

shared_ptr的拷贝和赋值1、当新的 shared_ptr 对象与指针关联时,则在其构造函数中,将与此指针关联的引用计数增加1。2、当任何 shared_ptr 对象超出作用域时,则在其析构函数中,它将关联指针的引用计数减1。如果引用计数变为0,则表示没有其他 shared_ptr 对象与此内存关联,在这种情况下,它使用delete函数删除该内存。

auto p=make_shared&lt;int&gt;(42) //p指向的对象只有p一个引用者

auto q(p) //p和q指向相同对象,此对象有两个引用者

检查 shared_ptr 对象的引用计数

p1.use_count();

完整实例

#include &lt;iostream&gt;

#include &lt;memory&gt; // 需要包含这个头文件


int main()

{

    // 使用 make_shared 创建空对象

    std::shared_ptr&lt;int&gt; p1 = std::make_shared&lt;int&gt;();

    *p1 = 78;

    std::cout &lt;&lt; "p1 = " &lt;&lt; *p1 &lt;&lt; std::endl; // 输出78


    // 打印引用个数:1

    std::cout &lt;&lt; "p1 Reference count = " &lt;&lt; p1.use_count() &lt;&lt; std::endl;


    // 第2个 shared_ptr 对象指向同一个指针

    std::shared_ptr&lt;int&gt; p2(p1);


    // 下面两个输出都是:2

    std::cout &lt;&lt; "p2 Reference count = " &lt;&lt; p2.use_count() &lt;&lt; std::endl;

    std::cout &lt;&lt; "p1 Reference count = " &lt;&lt; p1.use_count() &lt;&lt; std::endl;


    // 比较智能指针,p1 等于 p2

    if (p1 == p2) {

        std::cout &lt;&lt; "p1 and p2 are pointing to same pointer\n";

    }


    std::cout&lt;&lt;"Reset p1 "&lt;&lt;std::endl;


    // 无参数调用reset,无关联指针,引用个数为0

    p1.reset();

    std::cout &lt;&lt; "p1 Reference Count = " &lt;&lt; p1.use_count() &lt;&lt; std::endl;

    

    // 带参数调用reset,引用个数为1

    p1.reset(new int(11));

    std::cout &lt;&lt; "p1 Reference Count = " &lt;&lt; p1.use_count() &lt;&lt; std::endl;


    // 把对象重置为NULL,引用计数为0

    p1 = nullptr;

    std::cout &lt;&lt; "p1 Reference Count = " &lt;&lt; p1.use_count() &lt;&lt; std::endl;

    if (!p1) {

        std::cout &lt;&lt; "p1 is NULL" &lt;&lt; std::endl; // 输出

    }

    return 0;

}


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。