Skip to content

Latest commit

 

History

History
426 lines (342 loc) · 11.5 KB

小技巧.md

File metadata and controls

426 lines (342 loc) · 11.5 KB

1 字符串转换成 整形 浮点型

// 使用输入输出流
    #include <iostream> //标准输入输出头文件
    #include <sstream> 
      float x_trans = 0.7;
      if(argc>=2) {
       std::istringstream xss(argv[1]);
       xss >> x_trans;
      }
// 使用库函数  整数等转string
int j=100;
string j_str = boost::chrono::to_string(j)

2 vector 结构体 以结构体中的成员查找

在vector中查找最先想到的自然是find函数

struct student{
    string name;
    int grade;
};

vector<student> stu;//就当数据已经存好了...

假设以name为查找对象

string str="john";
vector<student>::iterator it=find(stu.begin(),stu.end(),str);

此时迭代器it指示的就是我们查找的字符串所在的结构体在容器中的位置但是这显然是会出错的find的本质是将find的第三个参数与容器中的元素进行==操作string和student不管怎么样都不会相等的所以我们需要将student的==操作重写

bool student::operator ==(const string &x){
    return(this->name==x);
}    

3 查找多个符合条件的值

// 在结构体vector中查找符合条件的所有元素
// g++ test.cpp -o t
// ./t
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
#include<string>
using namespace std;
typedef struct StudentInfo {
 int id;
 string name;
} STUINFO;

// 奇数
bool IsOddId (STUINFO info) {
  return ((info.id%2)==1);
}

// 偶数
bool IsEvenId (STUINFO info) {
  return ((info.id%2)==0);
}

int main(int argc, char** argv)
{
	 vector<STUINFO> v;
	 vector<STUINFO>::iterator iter, it_end;
	  
	 STUINFO temp;
	 temp.id = 100;
	 temp.name = "Jack";
	 v.push_back(temp);
	 temp.id = 101;
	 temp.name = "Sam";
	 v.push_back(temp);
	 temp.id = 102;
	 temp.name = "John";
	 v.push_back(temp);
	 temp.id = 103;
	 temp.name = "Tom";
	 v.push_back(temp);
	 
         std::vector<vector<STUINFO>::iterator> candidate; // 符合条件的
	 iter = v.begin()-1;
	 it_end = v.end(); 
	 while(true) 
         {
	  // iter = find_if(++iter, v.end(), IsEvenId);// 偶数
          iter = find_if(++iter, v.end(), IsOddId);   // 奇数
	  if (iter != it_end )
	   // cout << "ID: " << (*iter).id << ", Name: " << (*iter).name <<endl;
           candidate.push_back(iter);
	  else
	   break;  
	 }
         for(int i=0; i<candidate.size(); i++)
             cout << "ID: " << (*candidate[i]).id << ", Name: " << (*candidate[i]).name <<endl;
 
         return 0;
}

4 linux无锁化编程

原子类型 不加锁下不担心内存反问冲突

linux无锁化编程--__sync_fetch_and_add系列原子操作函数

无锁编程实战演练

// 以count = 4为例,调用__sync_fetch_and_add(&count,1),之后,返回值是4,然后,count变成了5.
// 有 __sync_fetch_and_add , 自然也就有 __sync_add_and_fetch,呵呵这个的意思就很清楚了,先自加,再返回。
// 他们哥俩的关系与i++和++i的关系是一样的。
// 有了这个宝贝函数,我们就有新的解决办法了。对于多线程对全局变量进行自加,我们就再也不用理线程锁了。
在用gcc编译的时候要加上选项 -march=i686
// sam:在我的服务器上,发现不加都可以。
type __sync_fetch_and_add (type *ptr, type value);
type __sync_fetch_and_sub (type *ptr, type value);
type __sync_fetch_and_or (type *ptr, type value);
type __sync_fetch_and_and (type *ptr, type value);
type __sync_fetch_and_xor (type *ptr, type value);
type __sync_fetch_and_nand (type *ptr, type value);
type __sync_add_and_fetch (type *ptr, type value);
type __sync_sub_and_fetch (type *ptr, type value);
type __sync_or_and_fetch (type *ptr, type value);
type __sync_and_and_fetch (type *ptr, type value);
type __sync_xor_and_fetch (type *ptr, type value);
type __sync_nand_and_fetch (type *ptr, type value);

5 产生N个不重复的随机数的快速算法

//http://blog.csdn.net/devfun/article/details/6534476
//https://blog.csdn.net/devfun/article/details/6534476
int* RandPerm(int N)
{
    int i;
    int[] TempArray = new int[N];
    int[] Value = new resultArray[N];
    
    for (i = 0; i < N; i++) 
       TempArray[i] = i;// 0~n-1数组
       
    for (i = 0; i < N; i++)
    {
        int seed = random(0, N - i);//从剩下的随机数里生成  
        resultArray[i] = TempArray[seed];//赋值给结果数组  
        TempArray[seed] = TempArray[N - i - 1];//把随机数产生过的位置替换为未被选中的值。  	 
    }
    return resultArray;
}

6 在main函数之前执行代码-C语言__attribute__((constructor))

我们都知道main函数是C语言的入口函数,代码都是从main函数开始执行的。

那么问题来了,有没有办法让代码在main函数之前执行哪?

GCC语法支持的__attribute__属性
__attribute__((constructor)):在main函数之前执行某个函数;类似类的构造函数。
__attribute__((destructor)):在main函数之后执行某个函数;类似类的析构函数。

constructor和destructor会在ELF文件中添加两个段-.ctors和.dtors。

当动态库或程序在加载时,会检查是否存在这两个段,如果存在执行对应的代码。
#include <stdio.h>
 
void __attribute__((constructor)) before_main();
void __attribute__((destructor)) after_main();
 
int main()
{
	printf("Hello World!\n");
	return 0;
}
 
void before_main()
{
	printf("Before main\n");
}
 
void after_main()
{
	printf("After main\n");
}

/*
Before main
Hello World!
After main
*/

7 浮点数判等\等于零等...

// 浮点数判等
bool is_equal (double a, double b, double epsilon = 1.0e-7)
{
    return std::abs(a - b) < epsilon;
}
// 等于零
bool NearZero(const double val, double epsilon = 1.0e-6){
    return (std::abs(val) < epsilon);
}

8. 字符串(C风格)转换成整型 atoi()实现 重要溢出判断思路

int atoi_my(const char* const cs) {
    // 内置 atoi 不会处理 NULL 指针
    if (cs == nullptr) return 0;

    int ret = 0;
    auto *p = cs;  // cs 为常指针

    // 跳过前面的空格
    while (isspace(*p)) p++;

    // 判断正负
    int sign = 1;   // 默认正数
    if (*p == '-') sign = -1;
    if (*p == '-' || *p == '+') p++;

    // 核心代码:循环转换整数(加入溢出判断)=============================
    int tmp;  // 保存临时结果,用于溢出判断
    while (*p >= '0' && *p <= '9') {
        tmp = ret * 10 + (*p - '0');
        if (tmp / 10 != ret) {  // 溢出判断======== tmp/10的商 应该等于 ret====
            return sign > 0 ? INT_MAX : INT_MIN; // 溢出时,直接返回最大值 或最小值
        }
        ret = tmp;
        p++;
    }
    // 核心代码(无溢出判断)
    //while (*p >= '0' && *p <= '9') {
    //    ret = ret * 10 + (*p - '0');
    //    p++;
    //}

    return sign * ret;
}

9. 友元函数、友元类

友元函数
不是类的成员函数,却能访问该类所有成员(包括私有成员)的函数
类授予它的友元函数特别的访问权,这样该友元函数就能访问到类中的所有成员。
class A {
public:
    friend void set_data(int x, A &a);      // 类A的友元函数 的声明
    int get_data() { return data; }
private:
    int data;
};

void set_data(int x, A &a) {                // 友元函数的定义
    a.data = x; 
    cout << a.data << endl;                 // 该友元函数 可以 无障碍 读写 A类 的私有成员
}

int main(void) {
    class A a;
    set_data(1, a);
    // cout << a.data;  // err
    cout << a.get_data() << endl; 
    return 0;
}
友元类

一个类的 友元类 可以访问 该类的所有成员(包括私有成员)
注意点
友元关系不能被继承
友元关系不能传递
友元关系是单向的
class A {
public:
    friend class C;    // A类的 友元类 C 的声明:C 是 A 的友元类
private:
    int data;
};

class C {              // 友元类C 的定义,可以访问 类A 中的成员
public:
    void set_A_data(int x, A &a) { 
        a.data = x; 
    }

    int get_A_data(A& a) {
      return a.data;
    }
};

int main(void) {
    class A a;
    class C c;

    c.set_A_data(1, a);
    cout << c.get_A_data(a) << endl;  // 1

    return 0;
}

10.Eigen 矩阵相关

// 矩阵归一化,归一化矩阵
Eigen::MatrixXd Normalize(Eigen::MatrixXd V){
    V.normalize();
    return V;
}

// 向量转李代数,叉乘矩阵,反对称矩阵
Eigen::Matrix3d VecToso3(const Eigen::Vector3d& omg) {
    Eigen::Matrix3d m_ret;
    m_ret << 0, -omg(2), omg(1),
            omg(2), 0, -omg(0),
            -omg(1), omg(0), 0;
    return m_ret;
}

// 李代数矩阵(反对称矩阵) 转 向量
Eigen::Vector3d so3ToVec(const Eigen::MatrixXd& so3mat) {
    Eigen::Vector3d v_ret;
    v_ret << so3mat(2,1), so3mat(0,2), so3mat(1,0);
    return v_ret;
}

// 归一化向量+模
Eigen::Vector4d AxisAng3(const Eigen::Vector3d& expc3){
    Eigen::Vector4d v_ret;
    v_ret << Normalize(expc3), expc3.norm();
    return v_ret;
}

// 机器人相关库
https://github.com/Le0nX/ModernRoboticsCpp/blob/master/src/modern_robotics.cpp

11. 数组元素筛选,更新

//去除无法追踪的特征 输入特征点的状态标识数组
void reduceVector(vector<cv::Point2f> &v, vector<uchar> status)
{
    int j = 0;// j为剩余 状态良好的 特征点数量
    for (int i = 0; i < int(v.size()); i++)
        if (status[i]) // 特征点状态良好
            v[j++] = v[i];//j++表示先取出j的值,再加1
            // j为剩余 状态良好的 特征点数量
    v.resize(j);
}

//去除无法追踪到的特征点 特征点id数组 ;特征点的状态标识数组
void reduceVector(vector<int> &v, vector<uchar> status)
{
    int j = 0;// j为剩余 状态良好的 特征点数量
    for (int i = 0; i < int(v.size()); i++)
        if (status[i])    // 特征点状态良好
            v[j++] = v[i];//j++表示先取出j的值,再加1
            // j为剩余 状态良好的 特征点数量
    v.resize(j);
}

lambda匿名函数写法,方便排序

    //(cnt, pts, id)序列 追踪的次数:2d特征点:特征点id
    vector<pair<int, pair<cv::Point2f, int>>> cnt_pts_id;
    for (unsigned int i = 0; i < forw_pts.size(); i++)
        cnt_pts_id.push_back(make_pair(track_cnt[i], make_pair(forw_pts[i], ids[i])));

    //对光流跟踪到的特征点forw_pts,按照被跟踪到的次数从大到小排序
    sort(cnt_pts_id.begin(), cnt_pts_id.end(), 
         // 匿名函数 实现 两元素比较大小
         [](const pair<int, pair<cv::Point2f, int>> &a, const pair<int, pair<cv::Point2f, int>> &b)
         {
            return a.first > b.first;
         }
        );
	
// 结构体数据中 某项数据的范围
auto cmp_x = [](PointXYZPixel const& l, PointXYZPixel const& r) { return l.x < r.x; };
auto minmax_x = std::minmax_element(seg->begin(), seg->end(), cmp_x);// 点云x最大

	
// 结构体数据中某一项的均值
auto sum_x = [](double sum_x, PointXYZPixel const& l){return sum_x + l.x;};// 对某一项累计求和
auto sumx = std::accumulate(seg->begin(), seg->end(), 0.0, sum_x);// 求和
double mean_x =  sumx / seg->size(); // 均值


// 使用 外部数据(类内私有数据)
// 判断点云团是否足够大===
auto func = [this](pcl::PointIndices indices) { return indices.indices.size() < this->mObject_minimum_points; };
// 删除过小的点云团
cluster_indices.erase(std::remove_if(cluster_indices.begin(), cluster_indices.end(), func), cluster_indices.end());