2020-3-20-----------------------------------------------------------------------------------------------------------------------------------------------------------
class A{
A(input){
temp = input;
}
private:
int temp;
}
A a(5);
std::shared_ptr<A> p(new A);
std::shared_ptr<A> p = std::make_shared<A>(a);
std::shared_ptr<A> p = std::make_shared<A>(5);
make_shared后面跟A类的一个对象或者构造函数里的参数,都是可以的。
2020-3-17-----------------------------------------------------------------------------------------------------------------------------------------------------------vector可以assign(n, digit);可以resize(大小),改变size,过大capacity会自动扩容; 也可以 reserve主动扩容,改变capacity.
resize更大之后,好像默认赋值0;resize更小之后,size变小了,但是原来的位置可以访问,而且还是原来的值,物理内存上的内容并没有改变.
thread及时回收,防止资源泄露https://www.cnblogs.com/liangjf/p/9801496.html
多线程cmake设置:
find_package (Threads)
add_executable (myapp main.cpp ...)
target_link_libraries (myapp ${CMAKE_THREAD_LIBS_INIT})
互斥锁std::mutex和条件变量std::condition_variable
——> > > std::mutex: std::mutex是C++中最基本的互斥量,提供了独占所有权的特性,std::mutex提供了以下成员函数:
构造函数:std::mutex不允许拷贝构造,也不允许move拷贝,最初产生的mutex对象是处于unlocked状态的。
lock():调用线程将锁住该互斥量,线程调用该函数会发生以下3种情况:
(1)如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用unlock之前,该线程一直拥有该锁。
(2)如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。
(3)如果当前互斥量被当前调用线程锁住,则会产生死锁,,也就是说同一个线程中不允许锁两次。
unlock():解锁,释放对互斥量的所有权。
try_lock():尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞,线程调用该函数会出现下面3种情况:
(1)如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用unlock释放互斥量。
(2)如果当前互斥量被其他线程锁住,则当前调用线程返回false,而并不会被阻塞掉。
(3)如果当前互斥量被当前调用线程锁住,则会产生死锁。
条件变量std::condition_variable:
条件变量是并发程序设计中的一种控制结构。多个线程访问一个共享资源(或称临界区)时,不但需要用互斥锁实现独享访问以避免并发错误(称为竞争危害),在获得互斥锁进入临界区后还需要检验特定条件是否成立:C++11中引入了条件变量,其相关内容均在<condition_variable>中。这里主要介绍std::condition_variable类。
(1)、如果不满足该条件,拥有互斥锁的线程应该释放该互斥锁,把自身阻塞(block)并挂到(suspend)条件变量的线程队列中
(2)、如果满足该条件,拥有互斥锁的线程在临界区内访问共享资源,在退出临界区时通知(notify)在条件变量的线程队列中处于阻塞状态的线程,被通知的线程必须重新申请对该互斥锁加锁。
条件变量std::condition_variable用于多线程之间的通信,它可以阻塞一个或同时阻塞多个线程。std::condition_variable需要与std::unique_lock配合使用。std::condition_variable效果上相当于包装了pthread库中的pthread_cond_*()系列的函数。
当std::condition_variable对象的某个wait函数被调用的时候,它使用std::unique_lock(通过std::mutex)来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的std::condition_variable对象上调用了notification函数来唤醒当前线程。
std::condition_variable对象通常使用std::unique_lock<std::mutex>来等待,如果需要使用另外的lockable类型,可以使用std::condition_variable_any类。
std::condition_variable类的成员函数:
(1)、构造函数:仅支持默认构造函数,拷贝、赋值和移动(move)均是被禁用的。
(2)、wait:当前线程调用wait()后将被阻塞,直到另外某个线程调用notify_*唤醒当前线程;当线程被阻塞时,该函数会自动调用std::mutex的unlock()释放锁,使得其它被阻塞在锁竞争上的线程得以继续执行。一旦当前线程获得通知(notify,通常是另外某个线程调用notify_*唤醒了当前线程),wait()函数也是自动调用std::mutex的lock()。
wait分为无条件被阻塞和带条件的被阻塞两种。
——> > > 无条件被阻塞:调用该函数前,当前线程应该已经对unique_lock<mutex> lck完成了加锁。所有使用同一个条件变量的线程必须在wait函数中使用同一个unique_lock<mutex>。该wait函数内部会自动调用lck.unlock()对互斥锁解锁,使得其他被阻塞在互斥锁上的线程恢复执行。使用本函数被阻塞的当前线程在获得通知(notified,通过别的线程调用 notify_*系列的函数)而被唤醒后,wait()函数恢复执行并自动调用lck.lock()对互斥锁加锁。
——> > > 带条件的被阻塞:wait函数设置了谓词(Predicate),只有当pred条件为false时调用该wait函数才会阻塞当前线程,并且在收到其它线程的通知后只有当pred为true时才会被解除阻塞。因此,等效于while (!pred()) wait(lck).
(3)、wait_for:与wait()类似,只是wait_for可以指定一个时间段,在当前线程收到通知或者指定的时间超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其它线程的通知,wait_for返回,剩下的步骤和wait类似。
(4)、wait_until:与wait_for类似,只是wait_until可以指定一个时间点,在当前线程收到通知或者指定的时间点超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其它线程的通知,wait_until返回,剩下的处理步骤和wait类似。
(5)、notify_all: 唤醒所有的wait线程,如果当前没有等待线程,则该函数什么也不做。
(6)、notify_one:唤醒某个wait线程,如果当前没有等待线程,则该函数什么也不做;如果同时存在多个等待线程,则唤醒某个线程是不确定的(unspecified)。
条件变化存在虚假唤醒的情况,因此在线程被唤醒后需要检查条件是否满足。无论是notify_one或notify_all都是类似于发出脉冲信号,如果对wait的调用发生在notify之后是不会被唤醒的,所以接收者在使用wait等待之前也需要检查条件是否满足。
std::condition_variable_any类与std::condition_variable用法一样,区别仅在于std::condition_variable_any的wait函数可以接受任何lockable参数,而std::condition_variable只能接受std::unique_lock<std::mutex>类型的参数。
std::notify_all_at_thread_exit函数:当调用该函数的线程退出时,所有在cond条件变量上等待的线程都会收到通知。
参考:
https://www.cnblogs.com/depend-wind/articles/10108048.html
https://www.cnblogs.com/zhanghu52030/p/9166737.html
2020-3-11------------------------------------------------------------------------------------------------------------------------------------------------------------
基类A,包含a, b两个方法,其中a调用了b,且b是virtual;
派生类B,重写了b,还新写了个c函数;
基类指针p指向B的对象,不能调用c,因为他也不知道派生类会有这么个函数;
p调用函数a的时候,a又调用了函数b,因为是virtual的且B中也重写了,因此会调用B中的b。
2020-3-6---------------------------------------------------------------------------------------------------------------------------------------------------------------------
std::atan(y/x)
std::atan2(y, x)
atan的情况下,要保证x不会等于0;atan2允许x等于0,不需要特别考虑。做除法就要考虑分布会不会存在等于0的风险。
不要用abs(), fabs()这种c的库,统一用std::abs()
2020-3-5--------------------------------------------------------------------------------------------------------------------------------------------------------------------
enum 与enum class:
1.3 问题3:enum的作用域
enum的中的 ” { } ” 大括号并没有将枚举成员的可见域限制在大括号内,导致enum成员曝露到了上一级作用域(块语句)中。
例如:
#include <iostream>
enum color{red,blue};//定义拥有两个成员的enum,red和blue在enum的大括号外部可以直接访问,而不需要使用域运算符。
int main() {
std::cout << blue << std::endl;
std::cin.get();
return 0;
}
就如上面的代码,我们可以在blue的大括号之外访问它,color的成员被泄露到了该文件的全局作用域中(虽然它尚不具备外部链接性)。可以直接访问,而不需要域运算符的帮助。
但是这不是关键,有时我们反而觉得非常方便。下面才是问题所在:
问题:无法定义同名的枚举成员
enum color { red, blue };
//enum MyEnum { red, yellow }; ERROR, 重定义;以前的定义是“枚举数”
如上面的代码所示:我们无法重复使用red这个标识符。因为它在color中已经被用过了。但是,它们明明就是不同的枚举类型,如果可以使用相同的成员名称,然后通过域运算符来访问的话,该有多好!就像下面这样:
color::red
但是这是旧版的enum无法做到的。
引入了域,要通过域运算符访问,不可以直接通过枚举体成员名来访问(所以我们可以定义相同的枚举体成员而不会发生重定义的错误)
#include <iostream>
enum class color { red, green, yellow};
enum class colorX { red, green, yellow };
int main() {
//使用域运算符访问枚举体成员,强转后打印
std::cout << static_cast<int>(color::red) << std::endl;
std::cout << static_cast<int>(colorX::red) << std::endl;
std::cin.get();
return 0;
}
尽量用using而不是typedef
//typedef std::shared_ptr<FeatureInfo> FeatureInfo_Ptr;
using FeatureInfo_Ptr = std::shared_ptr<FeatureInfo>;
push_back(), 已知大小的情况下先reserve(),不需要随机访问的情况系下用list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
memset
memset()函数原型是extern void *memset(void *buffer, int c, int count) buffer:为指针或是数组,
c:是赋给buffer的值,
count:是buffer的长度.
int abs(int i); // 处理int类型的取绝对值
double fabs(double i); //处理double类型的取绝对值
float fabsf(float i); /处理float类型的取绝对值
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1、vector<Eigen::Matrix4d,Eigen::aligned_allocator<Eigen::Matrix4d>>
2、bitset
3、int*, static_cast<int*>, reinterpret_cast<int*>不一样;
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
定义为虚函数,继承之后存在同名函数,但是行为不同,可以使用基类指针或者引用指向;
BCD都继承自A,可以使用A指针指向,从而做到用数组“保存”不同类型的BCD,不管是什么类型,如果他们都存在与A的同名虚函数,那么调用的就是BCD各自的方法,如果没有定义为虚函数,那么在任何情况下调用的都是基类的方法;
如果不需要使用基类指针指向不同class,并调用同名函数,也没必须定义虚函数,反正也不影响调用父类的函数功能
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------chrono计时:
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
LandmarkFeatureExtracter::extract(scan, features);
GeometryFeatureExtracter::extract(scan, features);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::chrono::steady_clock::duration used_time = end-start;
std::cout << "used time: " << std::chrono::duration_cast<std::chrono::milliseconds>(used_time).count() << std::endl;