CMakeList # 设置CMake版本最低要求 cmake_minimum_required(VERSION 3.10)# 设置项目名称和版本 project(Tutorial VERSION 2.0)# 指定 C++ 标准 set(CMAKE_CXX_STANDARD 11)set(CMAKE_CXX_STANDARD_REQUIRED True)# 生成一个头文件,传递 CMake 的一些设置到源代码 configue_file(TutorialConfig.h.in TutorialConfig.h)# 添加源码文件和生成的目标文件的名称 add_executable(Tutorial main.cpp)# 添加头文件查找路径 target_include_directories(Tutorial PUBLIC "$(PROJECT_BINARY_DIR)")TutorialConfig.h.in // #define TUTORIAL_VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define TUTORIAL_VERSION_MINOR @Tutorial_VERSION_MINOR@
一、CMakeLists.txt 文件示例 # 设置CMake版本最低要求 cmake_minimum_required(VERSION 3.10)# 设置项目名称和版本 project(Tutorial VERSION 1.0)# 添加源码文件和生成的目标文件的名称 add_executable(Tutorial main.cpp)二、CMake 相关命令 cmake .. 含有 CMakeLists.txt 文件的路径,根据 CMakeLists.txt 文件构建对应的工程;
cmake .. -DUSE_MYMATH=OFF 将 CMake 编译选项 USE_MYMATH 设置为关闭状态,并构建工程
cmake .. -DCMAKE_BUILD_TYPE=Release 在Linux中设定 Release 版本,可设置的类型有 Debug、MinSizeRel、Release、RelWithDebInfo
指定编译工具为 MSVC(不同的 CMake 版本,命令写法不同):
cmake -G "Visual Studio 14 2015 Win64" cmake -G "Visual Studio 16 2019" -A x64 cmake -G "Visual Studio 16 2019" -A Win32 在 Windows 中使用 MinGW...
哈希表及处理冲突的方法
一、哈希法与哈希表 哈希法又称散列法、杂凑法以及关键字地址计算法等,相应的表称为哈希表。 这种方法的基本思想是:首先在元素的关键字 k 和元素的存储位置 p 之间建立一个对应关系 f,使得 p = f(k),f 称为哈希函数。 创建哈希表时,把关键字为 k 的元素直接存入地址为 f(k) 的单元;以后当查找关键字为 k 的元素时,再利用哈希函数计算出该元素的存储位置 p=f(k),从而达到按关键字直接存取元素的目的。 二、冲突 当关键字集合很大时,关键字值不同的元素可能会映象到哈希表的同一地址上,即 k1 ≠ k2,但 f(k1) = f(k2),这种现象称为冲突,此时称 k1 和 k2 为同义词。
三、哈希函数构造方法 构造哈希函数的原则是:
函数本身便于计算; 计算出来的地址分布均匀,即对任一关键字 k,f(k) 对应不同地址的概率相等,目的是尽可能减少冲突 常用的构造方法:
数字分析法 平方取中法 分段叠加法 除留余数法:假设哈希表长为 m,p 为小于等于 m 的最大素数,则哈希函数为 f(k)=k % p 伪随机数法 四、冲突处理方法 1. 开放地址法(Open addressing) 这种方法也称再散列法,其基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi
线性探测 二次探测 伪随机探测 线性探测再散列的优点是:只要哈希表不满,就一定能找到一个不冲突的哈希地址,而二次探测再散列和伪随机探测再散列则不一定;缺点是线性探测再散列容易产生二次聚集
2. 再哈希法 这种方法是同时构造多个不同的哈希函数,当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间...
一、结论 C 中将数据类型分为左值和右值,在 C++11 中又将右值概念更为细致的分为将亡值(xvalue)和纯右值(prvalue)。 将亡值是 C++11 新增的跟右值引用相关的表达式,通常是将要被移动的对象(移为他用),比如返回右值引用 T&& 的函数返回值、std::move 的返回值。 从性能上讲,左右值引用没有区别,传参使用左右值引用都可以避免拷贝。 右值引用可以直接指向右值,也可以通过 std::move 指向左值;而左值引用只能指向左值(const左值引用也能指向右值)。 作为函数形参时,右值引用更灵活。虽然 const 左值引用也可以做到左右值都接受,但它无法修改,有一定局限性。 可移动对象在需要拷贝且被拷贝者之后不再被需要的场景,建议使用 std::move 触发移动语义,提升性能。 我们可以在自己的类中实现移动语义,避免深拷贝,充分利用右值引用和 std::move 的语言特性。 std::move 本身只做类型转换,对性能无影响。 std::forward 同样也是做类型转换且更强大,move 只能转出来右值,forward 既可以转成右值,又可以转成左值。 函数最好不要返回函数体内局部变量的左值引用或右值引用。 二、注意事项 左值引用是具名变量值的别名 右值引用是不具名(匿名)变量的别名 引用是变量的别名,由于右值没有地址,没法被修改,所以左值引用无法指向右值,但是,const左值引用是可以指向右值的
const int &ref_a = 5; int a = 5; int &ref_a = a; // 左值引用指向左值,编译通过 int &ref_a = 5; // 左值引用指向了右值,会编译失败 右值引用的标志是 &&,顾名思义,右值引用专门为右值而生,可以指向右值,不能指向左值
int&& ref_a_right = 5; // ok int a = 5; int&& ref_a_left = a; // 编译不过,右值引用不可以指向左值 ref_a_right = 6; // 右值引用的用途:可以修改右值 事实上 std::move 移动不了什么,唯一的功能是把左值强制转化为右值,让右值引用可以指向左值。其实现等同于一个类型转换:static_cast<T&&>(lvalue)。 所以,单纯的 std::move(xxx) 不会有性能提升,从这个角度来讲,右值引用和左值引用的功能相似,都是原始变量的别名,至于移动后原始变量是否可用,取决于被移动的数据类型对于移动语义的具体实现。...
一、auto_ptr 特点 支持拷贝构造 支持赋值拷贝 支持 operator->/operator* 解引用 支持指针变量重置 保证指针持有者唯一(涉及所有权转移) 二、问题一:使用数组存储 auto_ptr std::vector<std::auto_ptr<People>> peoples; // 这里实例化多个people并保存到数组中 ... std::auto_ptr<People> one = peoples[5]; ... std::cout << peoples[5]->get_name() << std::endl; 原因在于 std::auto_ptr 支持 operator=,为了确保指针所有者唯一,这里转移了所有权,people[5] 变成了 null
三、问题二、函数传参 auto_ptr 类型 void do_somthing(std::auto_ptr<People> people){ // 该函数内不对people变量执行各种隐式/显示的所有权转移和释放 ... } std::auto_ptr<People> people(new People("jony")); do_something(people); ... std::cout << people->get_name() << std::endl; 原因在于 std::auto_ptr支持拷贝构造,为了确保指针所有者唯一,这里转移了所有权
四、unique_ptr 在11中,可以支持右值以及移动语义了,此时可以完全匹配auto_ptr的所有权管理,新增了 std::unique_ptr。std::unique_ptr 不仅加入了移动语义的支持,同时也关闭了左值拷贝构造和左值赋值功能!杜绝了上述场景的出现!但是,此时,需要使用其他的方案了。比如场景一中,std::unique_ptr类型变量不能使用vector保存了!
所以 std::auto_ptr 废弃了,由 std::unique_ptr 代替!
class Person{ public: int getAge()const{ return m_age; } void setAge(int age){ m_age = age; } private: int m_age{20}; }; unique_ptr<Person> Change(unique_ptr<Person> p){ p->setAge(30); return p; } int main() { unique_ptr<Person> pP(new Person); cout << pP->getAge() << endl; // unique_ptr<Person> pP2 = Change(pP); // error: unique_ptr 删除了拷贝构造,所以需要使用 move 关键字转移所有权 unique_ptr<Person> pP2 = Change(move(pP)); // pP = pP2; // error:unique_ptr 删除了 = 赋值构造 cout << "-------------" << endl; cout << pP2->getAge() << endl; cout << "-------------" << endl; if(pP == nullptr){ cout << "pP 变量已失效" << endl; } return 0; } 输出:...