C++内存泄漏检查工具——Valgrind(–tool = memcheck)
https://blog.csdn.net/qq_33271192/article/details/108696138
core_ dump文件 包括dump文件怎么用
https://blog.csdn.net/weixin_43935474/article/details/113814220
QProcess
Unix系统里,每行结尾只有“<换行>“,即”\n";windows系统里面,每行结尾是"<换行><回车>" ,即”\n\r"。
一个直接的后果是,Unix的文件在windows打开的话,所有的文字会变成一行;windows文件在Unix里打开的话,在每行的结尾可能会多出一个^M符号。但这个符号通常是直接看不出来的,可以用命令cat -A filename 来查看。
注:主要在linux中解决由于文件结尾产生的错误
方式一:dos2unix
下载并安装dos2unix
利用命令“dos2unix [filename]”完成转换
方式二:替换(vim+正则表达式)
利用命令“vim -b [filename]”打开该文件
在命令模式下输入:“%s/^M//g”或者“g/\^M/s/\^M//”
保存并退出
注意:方式二中“^M”的输入方式:ctrl+v+m
Qt::QTestLib单元测试框架
https://blog.csdn.net/ipfpm/article/details/109852908?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-109852908-blog-111667673.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-109852908-blog-111667673.pc_relevant_aa&utm_relevant_index=1
对core_dump进行调试
dump调试。
https://www.cnblogs.com/zxh1210603696/p/4157294.html
atomic Widget::pInstance{ nullptr };
Widget* Widget::Instance() {
Widget* p = pInstance;
if (p == nullptr) {
lock_guard lock{ mutW };
if ((p = pInstance) == nullptr) {
pInstance = p = new Widget();
}
}
return p;
}
可以看出上面的代码相比较之前的示例代码来说已经相当的简洁了,但是!!!有是但是!!!!在C++memory model中对static local variable,说道:The initialization of such a variable is defined to occur the first time control passes through its declaration; for multiple threads calling the function, this means there’s the potential for a race condition to define first.因此,我们将会得到一份最简洁也是效率最高的单例模式的C++11实现:
1 widget& widget::get_instance() {
2 static widget instance;
3 return instance;
4 }
QTableWidget是QTableView的子类。
主要的区别是QTableView可以使用自定义的数据模型来显示内容(也就是先要通过setModel来绑定数据源),而QTableWidget则只能使用标准的数据模型,并且其单元格数据是QTableWidgetItem的对象来实现的(也就是不需要数据源,将逐个单元格内的信息填好即可)。
这主要体现在QTableView类中有setModel成员函数,而到了QTableWidget类中,该成员函数变成了私有。
使用QTableWidget就离不开QTableWidgetItem。
QTableWidgetItem用来表示表格中的一个单元格,正个表格都需要用逐个单元格构建起来。
Shared_ptr
weak_ptr
unique_ptr
auto_ptr
粘包的处理方式:
a) 当时短连接的情况下,不用考虑粘包的情况
b) 如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包
c) 如果双方建立长连接,需要在连接后一段时间内发送不同结构数据
d) 发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。
e) 发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
f) 可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。
g) 等等
父类指针实例化子类对象时,析构父类指针,未进子类析构函数中,内存泄漏
https://blog.csdn.net/aozhan8497/article/details/102348065
https://blog.csdn.net/qq_41278986/article/details/117532897
https://www.codedump.info/post/20191214-cxx11-memory-model-1/
https://www.codedump.info/post/20191214-cxx11-memory-model-2/
《深度探索c++对象模型》
https://blog.csdn.net/feng__shuai/article/details/108531439
使用说明:
解释:
很多人闹不清楚互斥锁和信号量的区别,觉得二者都是对资源加锁的操作,其实二者真正的区别是
互斥量是实现一个原子操作,也就是避免不同线程同时访问一个共享资源,导致出现异常;而信号量则是为了线程同步所设计的。
可以看出信号量是用来线程间同步用的,当信号量是二进制信号量的时候,也能用来充当mutex,
但是强烈建议不要这么使用,比如下面这个也能起到线程互斥的效果,但是按设计初衷来使用最好最安全。
T *
https://www.jianshu.com/p/81f0b071b3e0
std::thread
#include
void func(){}
int main()
{
std::thread thread(func);
thread.join(); //程序等待线程处理接收后再结束
//thread.detach(); //剥离线程 将子线程和主线程剥离开来 一般用join()
}
互斥锁 std::mutex
及 原子量 std::atomic
条件变量condition_variable
及 信号量 semaphore
std::condition_variable var //条件变量
var.notify_all(); var.notify_one(); //通知其他
var.wait(lock); //阻塞 相当于lock.unlock(); var.wait();
std::semaphore //C++20 信号量
承诺未来: std::promise
std::future
std::packaged_task
std::async
条件变量做了如下操作:
//wait传入的mutex互斥量必须为已加锁的
condition::wait(mutex)
{
...
mutex.unlock(); //1.对mutex进行解锁
WaitForSingleObjectEx(...) //2. 调用操作系统API 进行事件循环 阻塞在此处
//3.事件循环结束
mutex.lock(); //再对mutex进行加锁
}
//唤醒所有线程
//
condition::notify_all()
{
// wake up the all threads in the queue
QMutexLocker locker(&d->mtx);
for (int i = 0; i < d->queue.size(); ++i) {
QWaitConditionEvent *current = d->queue.at(i);
SetEvent(current->event);
current->wokenUp = true;
}
}
https://blog.csdn.net/lirongrong128/article/details/124434165
#include
#include
#include
#include
static int value = 0; // 产品数量
static bool ready = false; // 产品准备好标志
std::mutex lock_mutex; // 线程互斥量
std::condition_variable c_var; // 条件变量
// 工厂生产产品
void funB()
{
while (true){
std::unique_lock lock(lock_mutex);
// 生产产品过程
std::cout << "生产了产品,库存为:" << ++value << std::endl;
// 产品生产完毕
ready = true;
c_var.notify_all(); // 通知销售部可以卖产品了
c_var.wait(lock); // 假设最大库存为1个,工厂停工,仓库满了
}
}
// 销售产品
void funC()
{
while (true){
std::unique_lock lock(lock_mutex);
if (!ready) {
c_var.wait(lock); // 等待产品生产完毕
}
// 产品卖出去了
std::cout << "卖出了产品,库存为:" << --value << std::endl;
// 通知工厂赶紧生产,库存为空啦
ready = false;
c_var.notify_all();
}
}
// 主函数
int main(int argc, char *argv[])
{
std::thread fun_b_thread(funB);
std::thread fun_c_thread(funC);
fun_b_thread.join();
fun_c_thread.join();
return 0;
}
https://www.codedump.info/post/20191214-cxx11-memory-model-1/
https://www.codedump.info/post/20191214-cxx11-memory-model-2/
它对程序的执行结果有两个要求:
- 每个处理器的执行顺序和代码中的顺序(program order)一样。
- 所有处理器都只能看到一个单一的操作执行顺序。
- 在处理核心中增加写缓存,一个写操作只要写入到本核心的写缓存中就可以返回.
- SC是最简单直白的内存模型,TSO在SC的基础上,加入了写缓存,写缓存的加入导致了一些在SC条件下不可能出现的情况也成为了可能。
- 在松散型的内存模型中,编译器可以在满足程序单线程执行结果的情况下进行重排序(reorder)
- 在松弛型内存模型中,程序的执行顺序就不见得和代码中编写的一样了,这是这种内存模型和SC、TSO模型最大的差异。
- 由于有了缓冲区的出现,导致一些操作不用到内存就可以返回继续执行后面的操作,为了保证某些操作必须是写入到内存之后才执行,就引入了内存栅栏(memory barrier,又称为memory fence)操作。
- 内存栅栏指令保证了,在这条指令之前所有的内存操作的结果,都在这个指令之后的内存操作指令被执行之前,写入到内存中。也可以换另外的角度来理解内存栅栏指令的作用:显式的在程序的某些执行点上保证SC。
https://blog.csdn.net/xiaoxiaoguailou/article/details/123274253?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-1-123274253-blog-89318943.pc_relevant_multi_platform_whitelistv1&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-1-123274253-blog-89318943.pc_relevant_multi_platform_whitelistv1&utm_relevant_index=1
https://zhuanlan.zhihu.com/p/45566448
见上 memory model
在 C11/C++11 中,引入了六种不同的 memory order,可以让程序员在并发编程中根据自己需求尽可能降低同步的粒度,以获得更好的程序性能。这六种 order 分别是:
enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst
};
https://blog.csdn.net/linuxweiyh/article/details/79139766
https://blog.csdn.net/MeRcy_PM/article/details/50496683?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-50496683-blog-79139766.pc_relevant_multi_platform_whitelistv2&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-50496683-blog-79139766.pc_relevant_multi_platform_whitelistv2&utm_relevant_index=1
编译器可以对访存的指令进行乱序,减少逻辑上不必要的访存,以及尽量提高 Cache 命中率和 CPU 的 Load/Store 单元的工作效率。因此在打开编译器优化以后,有时会看到生成的汇编码并没有严格按照代码的逻辑顺序。
https://zhuanlan.zhihu.com/p/22469702
常见的分支预测器:
https://www.bilibili.com/video/BV1ZQ4y1S7mM?spm_id_from=333.337.search-card.all.click&vd_source=70d661a9d0aa9c59c89ab35d8afa922d
QT提供了对象树机制,能够自动、有效的组织和管理继承自QObject的对象。
每个继承自QObject类的对象通过它的对象链表(QObjectList
)来管理子类对象,当用户创建一个子对象时,其对象链表相应更新子类对象的信息,对象链表可通过children()获取。
当父类对象析构的时候,其对象链表中的所有(子类)对象也会被析构,父对象会自动,将其从父对象列表中删除,QT保证没有对象会被delete两次。开发中手动回收资源时建议使用deleteLater代替delete,因为deleteLater多次是安全的。
https://blog.csdn.net/qq_51604330/article/details/122483674?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-122483674-blog-118361160.pc_relevant_aa2&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-122483674-blog-118361160.pc_relevant_aa2&utm_relevant_index=1
https://blog.csdn.net/guuci/article/details/107410098
enum ConnectionType {
AutoConnection, // 默认连接方式 单线程 DirectConnection 多线程 DirectConnection
DirectConnection, // 单线程
QueuedConnection, // 多线程异步
BlockingQueuedConnection, // 多线程同步
UniqueConnection = 0x80 // 唯一连接,用来防止重复连接
};
元对象系统分为三大类:QObject类、Q_OBJECT宏和元对象编译器moc
Qt的类包含Q_OBJECT宏 moc编译器会对该类编译成标准的C++代码
QObject::event()
来交付事件。QCoreApplication::exec()
启动,QCoreApplication::exit()
结束,QCoreApplication::sendEvent()
和QCoreApplication::postEvent()
来手工产生事件。需要说明的是QCoreApplication::sendEvent()
会立即发送事件, QCoreApplication::postEvent()
则会将事件放在事件队列中分发。可以,shared_ptr可以复制,vector扩大
http://c.biancheng.net/view/482.html
std::vector> words;
words.push_back(std::make_unique("one"));
words.push_back(std::make_unique("two"));
vector 保存了 unique_ptr 类型的智能指针。make_unique() 函数可以生成对象和智能指针,并且返回后者。因为返回结果是一个临时 unique_ptr 对象,这里调用一个有右值引用参数的 push_back() 函数,因此不需要拷贝对象。另一种添加 unique_ptr 对象的方法是,先创建一个局部变量 unique_ptr ,然后使用 std::move() 将它移到容器中。然而,后面任何关于拷贝容器元素的操作都会失败,因为只能有一个 unique_ptr 对象。如果想能够复制元素,需要使用 shared_ptr 对象;否则就使用 unique_ptr 对象。
vector中元素的两个要求是:
1.元素必须能赋值
2.元素必须能复制
https://blog.csdn.net/virtual_func/article/details/49724135
不可以,引用不能复制
CLASS A 如何同步?
CLASS B
/*防止重复登录*/
QSystemSemaphore sema(mSystemFlag, 1, QSystemSemaphore::Open);
sema.acquire();// 在临界区操作共享内存 SharedMemory
QSharedMemory mem(appcationName);// 全局对象名
if (!mem.create(1))// 如果全局对象以存在则退出
{
sema.release();// 如果是 Unix 系统,会自动释放。
return 0;
}
...
sema.release();
QMutex mutex;
QWaitCondition condition;
bool flag = false;
int bufferSize = 0;
Thread Producer
{
public:
void run()
{
mutex.lock();
....
flag = true
condition.wait(&mutex);
mutex.unlock();
}
}
Thread Customer
{
public:
void run()
{
mutex.lock();
while(!flag)
{
condition.wait(&mutex);
}
flag = false;
condition.wakeAll();
mutex.unlock();
}
}
https://blog.csdn.net/TY113322/article/details/123343097
nullptr和NULL
lambda
for(a:b)
auto
decltype(针对表达式类型推导)
std::move
std::vector 声明再堆上
std::array 声明再栈上的,速度更快
std::tuple
等
C++98不能保证初始化线程的安全性
new出的对象数组必须要用delete[]删除,而普通数组delete和delete[]都一样
delete 结构体数组----都不会出问题!而delete 对象数组----报错。
https://blog.csdn.net/u010278318/article/details/8851724?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-8851724-blog-5930719.pc_relevant_multi_platform_whitelistv2&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-8851724-blog-5930719.pc_relevant_multi_platform_whitelistv2&utm_relevant_index=1
。C++ 里,如果 new 分配内存失败,默认是抛出异常的。所以,如果分配成功,p == 0 就绝对不会成立;而如果分配失败了,也不会执行 if ( p == 0 ),因为分配失败时,new 就会抛出异常跳过后面的代码。如果你想检查 new 是否成功,应该捕捉异常:
try {
int* p = new int[SIZE];
// 其它代码
} catch ( const bad_alloc& e ) {
return -1;
}
标准 C++ 亦提供了一个方法来抑制 new 抛出异常,而返回空指针:
int* p = new (std::nothrow) int; // 这样如果 new 失败了,就不会抛出异常,而是返回空指针
if ( p == 0 ) // 如此这般,这个判断就有意义了
return -1;
// 其它代码
…
shared_ptr中的引用计数是线程安全的 使用std::atomic原子锁
但是其内部的指针不是线程安全的 需要自己处理
https://blog.csdn.net/liang19890820/article/details/120465794
如果把 boost::shared_ptr 放到 unordered_set 中,或者用于 unordered_map 的 key,那么要小心 hash table 退化为链表。
http://stackoverflow.com/questions/6404765/c-shared-ptr-as-unordered-sets-key/12122314#12122314
直到 Boost 1.47.0 发布之前,unordered_set
https://svn.boost.org/trac/boost/ticket/5216
Boost 1.51 在 boost/functional/hash/extensions.hpp 中增加了有关重载,现在只要包含这个头文件就能安全高效地使用 unordered_set
了。
https://blog.csdn.net/ThinPikachu/article/details/121325198
协程不是系统进程,很多时候协程被称为"轻量级线程"、“微线程”、"纤程(fiber)"等。简单来说协程是(用户态)线程间里的不同函数,这些函数之间可以相互快速切换。
我们可以将线程分为 “内核态 “线程和” 用户态 “线程。
一个 “用户态线程” 必须要绑定一个 “内核态线程”,但是 CPU 并不知道有 “用户态线程” 的存在,它只知道它运行的是一个 “内核态线程”。
malloc/free和new/delete的共同点是:都是从堆上申请空间,并而需要手动释放,申请连续的空间一般是2个G,不同点是:
1.malloc和free是函数,new和delete是操作符
2.malloc申请的空间不会初始化,new可以初始化
3.malloc申请空间时,需要手动计算空间大小并传递,new只需要在其后跟空间的类型.如果是多个对象,[]中指定对象个数即可.
4.malloc返回值类型为void* ,在使用时必须强转,new不需要,因为new后面跟的是空间的类型
5.malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
6.申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数和析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调动析构函数完成空间中资源的清理
7.malloc/new申请空间本质上是把一块内存的实用权给你,不用空间了,free/delete释放内存空间的本质,是交还使用权给系统,那么系统就可以再分配给别人了.
全局变量在数据段 静态全局变量在静态区
静态局部变量在静态区 局部变量在栈区
使用 char* p = new char[100]申请一段内存,然后使用delete p释放,对于内置类型,delete就相当于free,而对于自定义类型则需要delete []来释放堆上的空间.
堆无法静态分配内存,只能动态申请,
https://blog.csdn.net/f110300641/article/details/106618519?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2aggregatepagefirst_rank_ecpm_v1~rank_v31_ecpm-3-106618519-null-null.pc_agg_new_rank&utm_term=qt%E7%9A%84deletelater&spm=1000.2123.3001.4430