c++ basic

Posted on August 12, 2021   10 minute read ∼ Filed in  : 

Valgrind工具包

https://phenix3443.github.io/notebook/software-engineering/debug/valgrind-practices.html

常见错误

1. unordered_map

unordered_map 定义的key需要加一个template hash 方法,否则会报错:

implicit instantiation of undefined template 'std::__1::hash<KID>'

Cmake语法规则

https://blog.csdn.net/DinnerHowe/article/details/80455172

file

file(GLOB variable [RELATIVE path] [globbingexpressions]…)

GLOB 会产生一个由所有匹配globbing表达式的文件组成的列表,并将其保存到变量中。Globbing 表达式与正则表达式类似,但更简单。如果指定了RELATIVE 标记,返回的结果将是与指定的路径相对的路径构成的列表。 (通常不推荐使用GLOB命令来从源码树中收集源文件列表。

原因是:如果CMakeLists.txt文件没有改变,即便在该源码树中添加或删除文件,产生的构建系统也不会知道何时该要求CMake重新产生构建文件。globbing 表达式包括:

  *.cxx   - match all files with extension cxx
  *.vt?   - match all files with extension vta,...,vtz
  f[3-5].txt - match files f3.txt,f4.txt, f5.txt

add_custom_target

添加一个目标,它没有输出;这样它就总是会被构建。

  add_custom_target(Name [ALL] [command1 [args1...]]
                    [COMMAND command2 [args2...] ...]
                    [DEPENDS depend depend depend ... ]
                    [WORKING_DIRECTORY dir]
                    [COMMENT comment] [VERBATIM]
                    [SOURCES src1 [src2...]])

  用Name选项给定的名字添加一个目标,这个目标会引发给定的那些命令。这个目标没有输出文件,并且总是被认为是过时的,即使那些命令试图去创建一个与该目标同名的文件。

使用ADD_CUSTOM_COMMAND命令可以生成一个带有依赖性的文件。默认情况下,没有目标会依赖于自定义目标。使用ADD_DEPENDENCIES命令可以添加依赖于该目标或者被该目标依赖的目标。如果指定了ALL选项,这表明这个目标应该被添加到默认的构建目标中,这样它每次都会被构建(命令的名字不能是ALL)。命令和选项是可选的;如果它们没有被指定,将会产生一个空目标。如果设定了WORKING_DIRECTORY参数,该命令会在它指定的路径下执行。如果指定了COMMENT选项,后跟的参数将会在构件的时候,在命令执行之前,被显示出来。DEPENDS选项后面列出来的依赖目标可以引用add_custom_command命令在相同路径下(CMakeLists.txt)生成的输出和文件。

C++知识点

import包

1,系统自带的头文件用尖括号括起来,这样编译器会在系统文件目录下查找。

#include 2, 用户自定义的文件用双引号括起来,编译器首先会在用户目录下查找,然后在到C++安装目录(比如VC中可以指定和修改库文件查找路径,Unix和Linux中可以通过环境变量来设定)中查找,最后在系统文件中查找。 #include “xxx.h”

传参数

  1. int, bool, float, double,

    value
    
  2. string, all others,

    const &var_name;
    
  3. xiu gai

    *varname
    

namespace

c++ 4层作用域,文件,函数,类,复合语句。

如果不同文件定义了相同名字的类, 主函数include了2个文件后,调用类名会出错。引入namespace后,可以根据namespace: className:methodName 来调用。

peopleA.h:

namespace peopleA
  class Student {
    public:
    ...
  }

peopleB.h:

namespace peopleB
  class Student {
    public:
    ...
  }

Main.cpp

#include "peopleA.h"
#include "peopleB.h"
int main(){
  peopleA:Student stud1();
  peopleB:Studnet stud2();
  return 0;
}

STD::move

string str1("hello");
string &&str2 = move(str1);
string &&str3 = move(str1);
cout << "str1: " << str1 << endl; // hello
cout << "str2: " << str2 << endl; // hello
cout << "str3: " << str3 << endl; // hello

string str4(move(str1));
cout << "str1: " << str1 << endl; // 
cout << "str4: " << str4 << endl; // hello

explicit

explicit只能用于类内部的构造函数声明,加了后不允许隐式转换类型。这样可以在编译阶段给出错误,避免一些不必要的错误。

类型转换可以是隐式转换类型也可以是显示类型转换,

显式转换类型:

A a{1};
# a 从类型A到类型B
B b = static_cast<B>(a);

enum

枚举类型,一个类定义为枚举类型,那么他的值只能是当中取一个。

enum class TransactionState 
{ GROWING, SHRINKING, COMMITTED, ABORTED };

inline

在系统下,栈空间(放置程序的局部数据, 也就是函数内数据, 的内存空间)是有限的,假如频繁大量的使用就会造成因栈空间不足而导致程序出错的问题,如,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。

为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。

在内部的工作就是在每个 for 循环的内部任何调用 callee(i)* 的地方都换成了 **(i%2>0)?1:2,这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗。

inline 只适合函数体内代码简单的函数使用,不能包含复杂的结构控制语句例如 while、switch,并且不能内联函数本身不能是直接递归函数。

inline 函数仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思,它如果认为函数不复杂,能在调用点展开,就会真正内联,并不是说声明了内联就会内联,声明内联只是一个建议而已。

建议 inline 函数的定义放在头文件中

内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。

atomic

可以实现不显示加锁,多线程互斥访问同一个变量的目的。

Lambda表达式

格式

[capture list] (params list) mutable exception-> return type { function body }
capture list:捕获外部变量列表
params list:形参列表
mutable指示符:用来说用是否可以修改捕获的变量
exception:异常设定
return type:返回类型
function body:函数体

examples:

[](int a, int b) -> bool { return a < b; }
int a = 123;
auto f = [a] { cout << a << endl; }; 
f(); // 输出:123
int a = 123;
auto f = [=] { cout << a << endl; };    // 值捕获
f(); // 输出:123
int a = 123;
auto f = [&] { cout << a << endl; };    // 引用捕获
a = 321;
f(); // 输出:321
捕获形式 说明
[] 不捕获任何外部变量
[a,b,c..] 默认以值得形式捕获指定的多个外部变量(用逗号分隔),如果引用捕获,需要显示声明(使用&说明符)
[this] 以值的形式捕获this指针
[=] 以值的形式捕获所有外部变量
[&] 以引用形式捕获所有外部变量
[=, &x] 变量x以引用形式捕获,其余变量以传值形式捕获
[&, x] 变量x以值的形式捕获,其余变量以引用形式捕获

Mutex锁

https://blog.csdn.net/faihung/article/details/88411839

https://blog.csdn.net/ktigerhero3/article/details/78249266

unordered_map 和map用法

https://blog.csdn.net/jingyi130705008/article/details/82633778

Map:

  1. 红黑树,数据有序,查询,插入,删除 O(logn)
  2. 自定义的key需要实现operator <
#include<iostream>
#include<map>
#include<string>
using namespace std;
int main()
{
	// 构造函数
	map<string, int> dict;
	
	// 插入数据的三种方式
	dict.insert(pair<string,int>("apple",2));
	dict.insert(map<string, int>::value_type("orange",3));
	dict["banana"] = 6;
 
	// 判断是否有元素
	if(dict.empty())
		cout<<"该字典无元素"<<endl;
	else
		cout<<"该字典共有"<<dict.size()<<"个元素"<<endl;
 
	// 遍历
	map<string, int>::iterator iter;
	for(iter=dict.begin();iter!=dict.end();iter++)
		cout<<iter->first<<ends<<iter->second<<endl;
 
	// 查找
	if((iter=dict.find("banana"))!=dict.end()) //  返回一个迭代器指向键值为key的元素,如果没找到就返回end()
		cout<<"已找到banana,其value为"<<iter->second<<"."<<endl;
	else
		cout<<"未找到banana."<<endl;
 
	if(dict.count("watermelon")==0) // 返回键值等于key的元素的个数
		cout<<"watermelon不存在"<<endl;
	else
		cout<<"watermelon存在"<<endl;
	
	pair<map<string, int>::iterator, map<string, int>::iterator> ret;
	ret = dict.equal_range("banana"); // 查找键值等于 key 的元素区间为[start,end),指示范围的两个迭代器以 pair 返回
	cout<<ret.first->first<<ends<<ret.first->second<<endl;
	cout<<ret.second->first<<ends<<ret.second->second<<endl;
 
	iter = dict.lower_bound("boluo"); // 返回一个迭代器,指向键值>=key的第一个元素。
	cout<<iter->first<<endl;
	iter = dict.upper_bound("boluo"); // 返回一个迭代器,指向值键值>key的第一个元素。
	cout<<iter->first<<endl;
	return 0;
}
// 自定义key
struct person  
{  
    string name;  
    int age;  
  
    person(string name, int age)  
    {  
        this->name =  name;  
        this->age = age;  
    }  
  
    bool operator < (const person& p) const  
    {  
        return this->age < p.age;   
    }  
};  
  
map<person,int> m;

Unordered_map:

  1. 哈希表(开链法), 时间复杂度为O(1)
  2. key需要定义hash_value函数并且重载operator ==
#include<string>  
#include<iostream>  
#include<unordered_map>
using namespace std;  
  
int main()
{
	unordered_map<string, int>  dict; // 声明unordered_map对象
	
	// 插入数据的三种方式
	dict.insert(pair<string,int>("apple",2));
	dict.insert(unordered_map<string, int>::value_type("orange",3));
	dict["banana"] = 6;
	
	// 判断是否有元素
	if(dict.empty())
		cout<<"该字典无元素"<<endl;
	else
		cout<<"该字典共有"<<dict.size()<<"个元素"<<endl;
	
	// 遍历
	unordered_map<string, int>::iterator iter;
	for(iter=dict.begin();iter!=dict.end();iter++)
		cout<<iter->first<<ends<<iter->second<<endl;
	
	// 查找
	if(dict.count("boluo")==0)
		cout<<"can't find boluo!"<<endl;
	else
		cout<<"find boluo!"<<endl;
	
	if((iter=dict.find("banana"))!=dict.end())
		cout<<"banana="<<iter->second<<endl;
	else
		cout<<"can't find boluo!"<<endl;
	
	return 0;
}

condition_variable

cv.wait(lock, [] { return ready; }); 相当于:while (!ready) { cv.wait(lock); }
#include <iostream>                // std::cout
#include <thread>                // std::thread, std::this_thread::yield
#include <mutex>                // std::mutex, std::unique_lock
#include <condition_variable>    // std::condition_variable

std::mutex mtx;
std::condition_variable cv;

int cargo = 0;
bool shipment_available()
{
    return cargo != 0;
}
// 消费者线程.
void consume(int n)
{
    for (int i = 0; i < n; ++i) {
        std::unique_lock <std::mutex> lck(mtx);
        cv.wait(lck, shipment_available);
        std::cout << cargo << '\n';
        cargo = 0;
    }
}

int main()
{
    std::thread consumer_thread(consume, 10); // 消费者线程.
    // 主线程为生产者线程, 生产 10 个物品.
    for (int i = 0; i < 10; ++i) {
        while (shipment_available())
            std::this_thread::yield();
        std::unique_lock <std::mutex> lck(mtx);
        cargo = i + 1;
        cv.notify_one();
    }
    consumer_thread.join();
    return 0;
}




END OF POST




Tags Cloud


Categories Cloud




It's the niceties that make the difference fate gives us the hand, and we play the cards.