c ++ 学习总结

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;
}

参考:https://blog.csdn.net/sanoseiichirou/article/details/50180533?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

尽量用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;

https://www.cnblogs.com/bianchengnan/p/9478638.html

发布了112 篇原创文章 · 获赞 15 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_39458342/article/details/102743909