赞
踩
auto func = [&epsilon](const TrajectoryPoint& tp,const double relative_time) {
return tp.relative_time() + epsilon < relative_time;};
auto it_lower = std::lower_bound(begin(), end(), relative_time, func);
}//[]内的参数由外界获取,()内的参数由调用时传入
sizeof测量传入变量的类型的大小
strlen 参数为字符指针,从该指针所在位置开始,往后遍历,直到遇到‘\0’,不包含‘\0’。要求传入的必须是指针,不能传入string类型的对象
为获取一个变量或表达式的类型
char s[]=”hello world”;
sizeof(s) //12,包含了最后一个NULL字符
strlen(s) //11 ,不包含最后一个NULL字符
char *s=”hello world”;
sizeof(s) //8 ,字符类型指针所占内存大小
strlen(s) //11
string s=”hello world”;
sizeof(s) //32
strlen(s) //error,s不是一个字符串,需要strlen(s.c_str())或strlen(s.data());针对string s;strlen(s)根本就是错误的,因为strlen的参数是一个字符指针,如果想用strlen得到s字符串的长度,应该使用sizeof(s.c_str()),因为string的成员函数c_str()返回的是字符串的首地址。实际上,string类提供了自己的成员函数来得到字符串的容量和长度,分别是Capacity()和Length()。string封装了常用了字符串操作,所以在C++开发过程中,最好使用string代替C类型的字符串。
strlen(s.c_str()) //11
s.capacity() //15
s.length() //11
s.size() //11
std::sort(first_encounter_overlaps_.begin(),first_encounter_overlaps_.end(),[](const std::pair<OverlapType, hdmap::PathOverlap>& a,const std::pair<OverlapType, hdmap::PathOverlap>& b)
{
return a.second.start_s < b.second.start_s;
});
%运算符用于int,fmod用于double/float等 取余
double NormalizeAngle(const double angle) {
double a = std::fmod(angle + M_PI, 2.0 * M_PI);
if (a < 0.0) {
a += (2.0 * M_PI);
}
return a - M_PI;
}
atan2接收两个输入参数;atan只接收一个输入参数
atan2对象限敏感,根据两个参数判断它是属于哪个象限并给出对应的角度值,值域范围[-pi, pi];atan对象限不敏感,值域范围为(-pi/2, pi/2]
该函数的作用是“去除”容器或者数组中相邻元素的重复出现的元素,注意
(1)这里的去除并非真正意义的erase,而是将重复的元素放到容器的末尾,返回值是去重之后的尾地址。
(2)unique针对的是相邻元素,所以对于顺序顺序错乱的数组成员,或者容器成员,需要先进行排序,可以调用std::sort()函数
学一学下面的unique的写法:
std::sort(polygon_points.begin(), polygon_points.end(),
[](const std::pair<STPoint, STPoint>& a,
const std::pair<STPoint, STPoint>& b) {
return a.first.t() < b.first.t();
});
auto last = std::unique(polygon_points.begin(), polygon_points.end(),
[](const std::pair<STPoint, STPoint>& a,
const std::pair<STPoint, STPoint>& b) {
return std::fabs(a.first.t() - b.first.t()) <
kStBoundaryDeltaT;
});
polygon_points.erase(last, polygon_points.end());
vector<int> a(b);
vector<int> a={1,2};
vector<int> a{1,2,3};
vector<int> list {1,2,3,4,5,6,7};//列表中元素的拷贝 然后
vector<int> list3(list.begin()+2, list.end()-1); 本例中list3被初始化为{3,4,5,6} or vector<int> a(m,n); //包含m个n
a.pop_back(); //删除最后一个数据,vector在不为空的前提下
a.erase(iterator first,iterator second);//删除指定范围内的数据:[first,second)遍历时需要注意,被删除的元素处iterator不能再继续使用
vector<int>::iterator iter = vec.begin() + 4; vec.erase(iter);//删除该容器第5个位置的数,erase不释放内存,只是将该位置初始化为默认值
std::remove(iterator first,iterator end,int val);//删除等于val的元素,返回最后一个!=val的元素下一个位置。
std::vector<A> * ptr;//访问方式at,提供有界保护
ptr->at(i);
reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。
是改变容器的大小,并且创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。resize就是重新分配大小,reserve就是预留一定的空间
vector<vector<int>> double_arr(double_arr_size);
double_arr.emplace_back(10);
emplace
vector<int> a;
vector<vector <int>> s;
for (int i = 1; i <= 10; i++)
a.push_back(i);
s.emplace_back(a.begin(), a.end());
s.emplace(s.begin(), a.crbegin(), a.crend());//在s的开始位置插入
emplace_back(可以直接在这里构造);//快速添加元素,例如reference_line_info_.emplace_back(reference_line_info类的构造参);例如:obstacles.emplace_back(new Obstacle(obstacle_id,prediction_obstacle.perception_obstacle(),trajectory, prediction_obstacle.priority().priority(), prediction_obstacle.is_static()));
push_front() //从头部插入元素
clear();
pop_back() //弹出尾部元素
pop_front() //弹出头部元素
front() //访问第一个元素 【例】int &first=list.front();
back() //访问最后一个元素 【例】 int &last=list.back();
reference_line_info_.sort([](a,b){return a.first<b.first});//对列表中的元素进行排序:
string s="abcd";
string s("hello world");
string a(10,'a');
string s[2] = {"Tom", "Jerry"};
string a=b+c;//b,c为string
std::string str1 = "45";
std::string str2 = "3.14159";
std::string str3 = "31337 with words";
std::string str4 = "words and 2";
int myint1 = std::stoi(str1);
int myint2 = std::stoi(str2);
int myint3 = std::stoi(str3);
std::cout << "std::stoi(\"" << str1 << "\") is " << myint1 << '\n'; //std::stoi("45") is 45
std::cout << "std::stoi(\"" << str2 << "\") is " << myint2 << '\n'; //std::stoi("3.14159") is 3
std::cout << "std::stoi(\"" << str3 << "\") is " << myint3 << '\n'; //std::stoi("31337 with words") is 31337
string s="12";
int i=atoi(s.c_str());
C++引入了ostringstream、istringstream、stringstream这三个类,要使用他们创建对象就必须包含sstream.h头文件。
istringstream类用于执行C++风格的串流的输入操作;
ostringstream类用于执行C风格的串流的输出操作;
stringstream类同时可以支持C风格的串流的输入输出操作。
istringstream s="12";
int i;
s>>i; //此时i的内容为12
s.erase(s.begin());//去除字符串首个元素
s.erase(s.end()-1);//去除字符串最后面元素:
s.erase(s.begin()+i);//去除字符串下标为i的元素:官方提供的erase操作O(n)
t.find(s)!=std::string::npos
s.resize(s.size()+10);//resize不会弄丢之前的内容
s=s.replace(‘a’,'b');//将s中的'a'替换为‘b’
s.split()
reverse(s.begin(),s.end());
s.pop_back();
s.push_back('#');
stack<int> st;
int result=st.top();
queue qu;
int result=qu.front();//返回queue qu的开头元素
qu.pop();//删除qu的开头元素
int result=qu.back();//返回qu的结尾元素
qu.push(x);//插入
deque<int> d1(d2begin(),d2.end());or deque<int> d1(d2); //用d2给d1初始化
deque<int> d2(10,100); //用10个100给d2初始化
deque<int> d1;
push_back();//方式一
operator = //方式二
d1.assign(d2.begin(),d2.end());//方式三
push_front(elem);//在容器头部插入一个数据
pop_back();//删除容器最后一个数据
pop_front();//删除容器的第一个数据
back(); //查看队尾元素
front(); //查看队首元素
d1.insert(d1.begin(),n,element);//在开头处插入n个element
d1.insert(d1.begin(),d2.begin(),d2.end());//同上
deque<int>::iterator it=d1.begin();
d1.erase(it);//删除值的方式 it为iterator的位置
缺省情况下priority_queue利用max-heap(大顶堆)完成对元素的排序,这个大顶堆是以vector为表现形式的complete binary tree(完全二叉树)。
class mycomparison {
public:
bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.second > rhs.second;
}
};
priority_queue<pair<int, int>, vector<pair<int, int>>,mycomparison> pri_que;
cout <<setiosflags(ios::fixed)<< setprecision(2) << 1/1.0 << endl;
unordered_map<string,string> u_map={{"教程1","welcome"},{"教程2","hello"},{"教程3","world"}};
un_map.find('a')!=un_map.end();
unordered_map<string,int> example;
example.insert(pair<string,int>("xiaoming",18));
example.insert(pair<string,int>("xiaohua",19));
example.insert({xxx,xxx});
or example[xxx]=xxxx;
cout<<example["xiaohua"]<<endl; //ok
cout<<example.at("xiaoming")<<endl; //ok
cout<<example.at("yyf")<<endl;//terminate called after throwing an instance of 'std::out_of_range'
example.erase(key);//删除
example.erase(iter);
clear();//全部删除
unordered_set<int> a(vec.begin(),vec.end()); //vec为vector类型对象
a.insert(10); //insert返回的第一个元素为指向当前新添加的元素的迭代器,第二个参数为表示成功与否的true or false; 失败的话迭代器指向重复的元素。
map_path_(std::move(std::vector<hdmap::MapPathPoint>(
reference_points.begin(), reference_points.end())));//给对象map_path_采用move方式进行赋值
std::size_t index=std::distance(xxx_list.cbegin(),iter);
std::lower_bound (accumulated_s.begin(), accumulated_s.end(),
s - look_backward));
std::upper_bound(accumulated_s.begin(), accumulated_s.end(),s + look_forward));
底层const进行拷贝时需要具有一置的属性,或者变量类型可以拷贝给const类型变量const int c=42;//指针常量,不能拷贝给非const类型的变量const int *p=c;//这里如果不加const就因属性不一致导致无法拷贝
//const初始化时就要赋值//const 常量的作用阈为本文件
int i=0;
const int *p=&i;//下层const,表示指针p无法改变变量i的值
int *const p1=&i;//上层const,表示指针p1指向变量i的内存空间后就不能再指向其他内存空间
auto map_msg = std::make_shared<MapMsg>();//无参构造//使用
or
std::make_shared<MapMsg> msg=nullptr;
msg.reset(new MapMsg());
msg->Process(xxxx);
relative_map_.Process(map_msg.get());//将std::make_shared<MapMsg>类型指针转变为MapMsg*
std::string FindFirstExist(const std::string& dir, const std::string& files){
const std::vector<std::string> candidates = absl::StrSplit(files, '|');
for (const auto& filename : candidates) {
const std::string file_path = absl::StrCat(FLAGS_map_dir, "/", filename);
if (cyber::common::PathExists(file_path)) {
return file_path;
}
}
}
std::reverse(points_.begin(), points_.end());
将double类型变量转化为int,static_cast<double>(待转换的变量);
map中的键是唯一的,默认按照键的值从小到大排序
map<string,int> mp;
mp['c']=20;//ok
cout<<mp['c']<<endl;//20
mp['c'] = 30; //30覆盖了20
map<typename1, typename2>::iterator it;
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++){
cout << it->first;
cout << " ";
cout << it->second;
cout << endl;
} //通过iterator来访问
find(key)返回键为key映射的迭代器,时间复杂度为O(logN),N为map中映射的个数
map<char, int> mp;
mp['a'] = 222;
mp['b'] = 333;
mp['c'] = 444;
map<char, int>::iterator it = mp.find('b');
cout << it->first << " " << it->second;//b 333
erase()有两种用法:1、删除单个元素。2、删除一个区间内所有的元素
删除单个元素:删除单个元素时间复杂度O(1)
map<char, int> mp;
mp['a'] = 222;
mp['b'] = 333;
mp['c'] = 444;
map<char, int>::iterator it = mp.find('b');
mp.erase(it);
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++){
cout << it->first << " " << it->second << endl;
}//a 222 c 444
mp.erase(key),key为要删除的映射的键。时间复杂度O(logN),N为map内元素的个数
map<char, int> mp;
mp['a'] = 222;
mp['b'] = 333;
mp['c'] = 444;
// map<char, int>::iterator it = mp.find('b');
// mp.erase(it);
mp.erase('b');
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++){
cout << it->first << " " << it->second << endl;
}//a 222 c 444
删除一个区间内所有的元素,mp.erase(first, last),其中,first为需要删除的区间的起始迭代器,last为需要删除的区间末尾迭代器的下一个地址,即为删除左闭右开的区间[first, last)。时间复杂度为O(last - first)
map<char, int> mp;
mp['a'] = 222;
mp['b'] = 333;
mp['c'] = 444;
map<char, int>::iterator it = mp.find('b');
mp.erase(it, mp.end()); //删除it之后的所有映射,即b 333和 c 444
//mp.erase(it);
//mp.erase('b');
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++){
cout << it->first << " " << it->second << endl;
}//a 222
size()用来获得map中映射的对数,复杂度为O(1)
clear()用来清空map中的所有元素,复杂度为O(N),N为map中元素个数
int i=20;
string s=i.to_string();
int i=20;
ostirngstream os;
string s;
os.str("");
os<<i;
os>>s;
int i=10;
ostringstream os;
os<<i;
cout<<os.str()<<endl;
C++引入了ostringstream、istringstream、stringstream这三个类,要使用他们创建对象就必须包含sstream.h头文件。
istringstream类用于执行C++风格的串流的输入操作。
ostringstream类用于执行C风格的串流的输出操作。
stringstream类同时可以支持C风格的串流的输入输出操作。
//提前告诉代码会输入多少个字符串
int n;
cin>>n;
cin.ignore(1,'\n');
vector<string> vc(n);
string temp;
for(int i=0;i<n;i++)
{
getline(cin,temp,'\n');
vc[i]=temp;
}
for(int i=0;i<n;i++)
cout<<vc[i]<<endl;
//不提前告诉会有多少个string
string s;
getline(cin,s,'\n');
stringstream ss;
ss<<s;
string temp;
vector<string> vec;
while(getline(ss,temp,' '))
{
vec.push_back(temp);
}
for(int i=0;i<vec.size();i++)
{
cout<<vec[i]<<endl;
}
1、初始化
std::multimap<int, std::string> myMultimap;
2、插入
myMultimap.insert(std::make_pair(1, "Apple"));
myMultimap.insert(std::make_pair(2, "Banana"));
myMultimap.insert(std::make_pair(2, "Blueberry"));
myMultimap.insert(std::make_pair(3, "Orange"));
3、删除
myMultimap.erase(myMultimap.begin());
3、打印
for (const auto& pair : myMultimap) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
4、查询指定键
int keyToFind = 2;
auto range = myMultimap.equal_range(keyToFind);
std::cout << "Values with key " << keyToFind << ": " << std::endl;
for (auto it = range.first; it != range.second; ++it) {
std::cout << it->second << std::endl;
}
static C++ 中常用的修饰符,用来控制变量的存储方式和可见性。
static的会被存储到全局(静态)存储区。
1)静态局部变量
在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。
a)静态局部变量在程序执行到该对象的声明处时被首次初始化(默认为0),即以后的函数调用不再进行初始化;
b)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。
不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组,如果不想让这个数组在函数调用结束释放可以使用 static 修饰。
2)全局静态变量
static 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以。
3)static修饰函数
static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。
4)static在类中的使用
static可以修饰类的成员函数和成员变量。
被 static 修饰的方法统一属于类的静态资源,是类实例之间共享的。静态成员变量只存储一份供所有对象共用,使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。
1、被static修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要new出一个类来
2、被static修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要new出一个类来
静态成员的定义或声明要加个关键字 static。静态成员可以通过双冒号来使用即 <类名>::<静态成员名>。
a. 类的对象可以使用静态成员函数和非静态成员函数,但不能通过类名来调用类的非静态成员函数。
b. 静态成员函数中不能引用非静态成员。
因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间。反之,类的非静态成员函数可以调用用静态成员函数。但类的静态成员变量在使用前必须先初始化。
(1)静态成员函数中不能调用非静态成员。
(2)非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。
(3)静态成员变量使用前必须先初始化(如 int MyClass::m_nNumber = 0;),否则会在 linker 时出错。
静态数据成员
(1)静态数据成员可以实现多个对象之间的数据共享,它是类的所有对象的共享成员,它在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。
(2)静态数据成员是在程序开始运行时被分配空间,到程序结束之后才释放,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。
(3)静态数据成员可以被初始化,但是只能在类体外进行初始化,若未对静态数据成员赋初值,则编译器会自动为其初始化为 0。
(4)静态数据成员既可以通过对象名引用,也可以通过类名引用。
静态成员函数
(1)静态成员函数和静态数据成员一样,他们都属于类的静态成员,而不是对象成员。
(2)非静态成员函数有 this 指针,而静态成员函数没有 this 指针。
(3)静态成员函数主要用来访问静态数据成员而不能访问非静态成员。
5)static修饰类的对象
单例模式
InfoRouterSignal& InfoRouterSignal ::GetInstance() {//单例模式
static InfoRouterSignal tcc;
return tcc;
}
1、一个进程包含多个线程,如果该进程没有额外创建其他线程,那么该进程本身就是一个主线程
2、子线程可以共享主线程的资源(主线程的局部变量除外),他们通过共享的数据进行相互通信
#include <iostream> #include <thread> #include <mutex> #include <stdlib.h> int cnt = 20; std::mutex m; void t1(){ while (cnt > 0) { std::lock_guard<std::mutex> lockGuard(m); // std::m.lock(); if (cnt > 0) { //sleep(1); --cnt; std::cout << cnt << std::endl; } // std::m.unlock(); } } void t2(){ while (cnt > 0) { std::lock_guard<std::mutex> lockGuard(m); // std::m.lock(); if (cnt > 0) { --cnt; std::cout << cnt << std::endl; } // std::m.unlock(); } } int main(void) { std::thread th1(t1); std::thread th2(t2); th1.join(); //等待t1退出 th2.join(); //等待t2退出 std::cout << "here is the main()" << std::endl; return 0; }
https://segmentfault.com/a/1190000002655852
enum struct light{
red,yellow,blue};
//访问
cout<<light::red<<endl;
enum class light{red,yellow,blue};//作用域位于class内部,不能隐式转换
//访问
cout<<light::red<<endl;
enum light{red,yellow,blue};//作用域与enum同级,可以隐式转换
//访问
cout<<light::red<<red<<endl;
enum {red,yellow,blue};//作用域与enum同级,可以隐式转换
//访问
cout<<red<<endl;
#include <chrono>
auto startTime = high_resolution_clock::now();
auto stopTime = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stopTime - startTime);
#include<chrono>
using namespace chrono;
milliseconds start_time = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
milliseconds end_time = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
cout << "耗时:" << end_time.count() - start_time.count() << "ms" << endl;
double timer;
timer = ros::Time::now().toSec();
double duration = (ros::Time::now().toSec() - timer) * 1000;
cout<<"耗时:"<<duration<<"ms"<<endl;
通过动态绑定来调用子类的virtual类型的成员函数,这样以后需要更改代码,只需要更换动态绑定的对象,即可完成后续所有功能开发
#include <iostream>
class Node {...};
class RootNode : public Node {...};
class SelfDrivingMode : public Node {...};
int main()
{
SelfDrivingMode* self_driving_mode = new SelfDrivingMode();
std::map<int, Node*> sub_nodes_; // 子节点集合
sub_nodes_.insert(std::make_pair(1, dynamic_cast<Node*>(self_driving_mode)));//向上转型
}
or
#include <iostream> class Animal { public: virtual void makeSound() { std::cout << "Animal makes a sound" << std::endl; } }; class Dog : public Animal { public: void makeSound() override { std::cout << "Dog barks" << std::endl; } }; int main() { Dog dog; Animal* animalPtr = &dog; // 将派生类对象赋值给基类指针 animalPtr->makeSound(); // 调用基类指针指向的对象的虚函数 return 0; }
#include <iostream> class Base { public: virtual void display() { std::cout << "Base class" << std::endl; } }; class Derived : public Base { public: void display() override { std::cout << "Derived class" << std::endl; } void extraFunction() { std::cout << "Extra function in Derived class" << std::endl; } }; int main() { Base* basePtr = new Derived(); // 使用 Derived 对象的地址初始化 Base 指针 Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); // 将 Base 指针转换为 Derived 指针 if (derivedPtr) { derivedPtr->display(); // 调用 Derived 类中的 display 函数 derivedPtr->extraFunction(); // 调用 Derived 类中的额外函数 } else { std::cout << "Failed to cast basePtr to derivedPtr" << std::endl; } delete basePtr; return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。