C++中如何引用第三方库
C++中如何引用第三方库?动态链接库和静态链接库在 C++中通常有两种链接 library:动态链接库(Dynamic Link Library,DLL)和静态链接库(Static Link Library,LIB)
动态链接库:在程序运行时通过链接器加载动态链接库,根据程序运行需要动态的链接需要的库中的数据。在 Linux 中,动态链接库通常以 .so 为扩展名(Shared Object),通常命名方式是lib.so.。
静态链接库:在编译链接阶段,静态链接库中的代码会被复制到 bin 中,因此编译的 bin 中是包含了静态链接库的代码的。在 Linux 中静态链接库通常以 .a 为扩展名(archive),通常命名位 lib.a。
引用库在使用第三方库时通常需要两个步骤:
在调用的文件中声明包含头文件,即:#include ""
在编译时链接库文件:
1g++ main.cpp -I/path/library/include -L/path/library -lexample_lib
-I 指定引用的头文件的路径-L 指定第三方库文件所在路径-l 指定 ...
C++函数返回值为引用类型
C++中函数返回值为引用类型有什么作用?函数返回值是引用类型主要三个场景:
函数返回值是一个很大的数据结构,避免拷贝开销;
实现函数的链式赋值操作,此时函数需要作为一个左值,经典的例子有:
std::cout << "hello, world" << std::endl;实际上执行的代码逻辑是: std::cout.operator<<("hello, world").operator<<(std::endl);
operator[]:当随机访问运算符需要实现赋值功能是,函数也需要是一个左值,因此函数需要返回引用类型;
1234567891011vector<int>& addElement(vector<int>& vec, int value) { vec.push_back(value); return vec;}int main() { vector<int> numbers; ...
C++中的整数类型
题目int,long,long long在 32 位 ,64 位和 64 位下跑 32 位虚拟机的大小
一般来说在 32 位系统上:int 通常为 4 字节(32位),long 通常为 4 字节(32 位),long long 通常为 8 字节(64 位)
在 64 位系统上:int 通常位 4 字节(32 位),long 通常为 8 字节(64 位),long long通常为8 字节(64 位)
并且大小只和系统位数有关,所以在虚拟机下也就只和虚拟机的操作系统有关所以在64 位下跑 32 位虚拟机和 32 位系统是一致的。
解释通常查询 C++20 ISO 14882 可以看到在 6.8.2 有关于基本类型的描述:
有五种标准signed integer type:
signed char
short int
int
long int
Long long int
并且按这个list 的顺序每种类型都至少要有和前面的类型一样多的空间。
另外还有一些 impl 定义的扩展 signed integer type,与标准 signed integer type 统称为 signed ...
enable_shared_from_this
Question:有一个类,这个类的对象是使用shared_ptr 管理的,在类内某个成员函数里,我们需要获取指向当前对象的 shared_ptr,应该如何获取?
可能的答案 1:
123456class A {public: std::shared_ptr<A> get_ptr() { return std::shared_ptr<A>(this); // 返回 this 指针的 shared_ptr }};
但是这样做是不安全的。在 get_ptr 中,会根据 this 指针创建一个完全独立的新的std::shared_ptr,这个 shared_ptr 有自己的引用计数,完全独立于当前类对象的 shared_ptr;这时这两个 shared_ptr 是同时在管理这个对象,如果新的这个shared_ptr 计数清零,它会尝试删除这个对象,造成未定义的行为。
正确的做法就是使用std::enable_shared_from_this
std::enable_shared_from_this是一个模板类,可以 ...
强制类型转换
C++有四种强制类型转换运算符:
static_cast: 可用于基本类型的转换,或者将指针转换为其他基本类型的指针,如:
12int i = 10;double d = static_cast<double>(i);
dynamic_cast: 用于基类和派生类之间的转换,包含了类型检查,只有在确定安全的情况下才会进行转换,否则就会 return nullptr;dynamic_cast 只能用于含有虚函数的类,且只能用于指针或引用。
const_cast: 用于修改类型的 const 和volatile 修饰词,对于 const 变量,可使用 const_cast 去除 const属性,然后才能改变变量的值;
123const int i = 10;int* p = const_cast<int*>(i);*p = 20;
reinterpret_cast: 是一种底层的强制类型转换,可以将任意类型的指针转换为任何其他类型的指针,reinterpret 会对变量进行机器(位)级别的重新解释,不进行任何类型检查和转换,属于非常危险的操作。
深拷贝和浅拷贝
深拷贝是指,在拷贝对象时复制对象所有的成员变量和成员函数,包括指针指向的动态分配的内存。这样拷贝出来的对象和原对象是完全独立的,对任意一方操作,另一方不会受到影响;
浅拷贝是指,在拷贝对象是只复制对象的成员变量,不会复制指针指向的动态分配的内存。这样拷贝出来的对象,它的指针成员变量和原对象是一块内存,操作任意一方都会修改这块内存,另一方也会受到影响。
所以浅拷贝之后再对任一对象操作,很容易出现内存泄漏或者悬空指针的问题。
C++中的锁
C++中的锁是为了实现多线程编程时线程的同步和互斥机制。在多线程编程中,多个线程可能同时访问一个共享资源,如果没有合适的同步和互斥机制,会出现数据竞争和死锁的问题。
读写锁:std::shared_mutex,读写锁允许多个线程同时对共享资源进行读操作,但是不可以同时进行写操作。当一个线程获取到读锁时,其他线程可以获取读锁,但是无法获取写锁;当一个线程获取到写锁时,其他线程读锁和写锁都无法获取。
互斥锁:std::mutex,互斥锁就是基本的锁,保证同一时间只有一个线程访问共享资源,当一个线程获取互斥锁时,其他线程不能获取锁,直到该线程锁释放。
条件变量:条件变量主要用于线程间通信,可以使用wait让一个线程等候另一个线程的通知,当要等候的线程准备完成后,可以使用notify_one/notify_all来通知等待的线程;条件变量可以通过 std::condition_variable 类来实现。
map容器的实现
一、map 容器的实现
map 容器底层的实现是红黑树,内部是按照键值排序的(无序的是 unordered_map)。map的实现保证插入、查找和删除时间复杂度是O(log n),而unordered_map则可以实现常数时间操作(内部由 hash table 实现)。
红黑树是一种自平衡二叉查找树,保证插入、查找和删除时间复杂度是O(log n)。
红黑树节点要么是红色,要么是黑色;
红黑树根节点是黑色的;
每个叶子节点都是黑色的;
如果一个节点是红色的,那么它的两个叶子节点是黑色的;
对于每个节点,从该节点到它的所有后代叶子的简单路径上,都包含相同数量的黑色节点。
红黑树的平衡性通过对节点的颜色的调整来实现的。当插入或删除节点时,会破坏红黑树的平衡性,那么就需要旋转和重新分配颜色。
了解vector容器
一、迭代器
在遍历容器时删除元素会导致迭代器失效,这是因为删除元素时改变了容器内元素的位置,从而让迭代器指向的元素位置不再有效。
如果要在遍历时删除元素,可以使用 erase 函数,erase 函数会返回指向被删除元素的下一个元素的迭代器,因此不会使迭代器失效。
12345678910111213#include <vector>int main() { std::vector<int> n{1,2,3,4,5}; for (auto it = n.begin(); it != n.end();) { if (*it % 2 == 0) { it = n.erase(it) } else { ++it; } }}
C++的内存对齐
C++的内存对齐是指将数据存储在内存中时,会按照一定规则将数据的起始地址对齐到特定的地址上。在计算机中,数据的存储和访问通常是以字节为单位,而不是以位为单位的,内存对齐可以提升数据访问的效率。
提高数据访问效率。数据按照内存对齐规则时,CPU 可以一次读写多个数据,不需要多次访问内存;
减少内存碎片。按照规则对齐的数据大小通常是 2 的幂次方,避免出现奇怪的内存碎片;
提高缓存命中率:内存对齐可以提高缓存命中率。现代 CPU 中通常都有多级缓存,缓存的大小和行大小都是有限制的。当数据按照规则对齐时,它们可以更好地利用缓存行,从而提高缓存命中率。
保证数据正确性:内存对齐可以保证数据的正确性。当数据按照规则对齐时,可以避免出现数据对齐错误的情况,从而保证数据的正确性。


