Qt的HelloWorld程序分析

一、Qt的HelloWorld程序

在Qt中编写HelloWorld程序,如下所示:

#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[])
{
    
    
    QApplication app(argc, argv);

    QLabel label("Hello, world");
    label.show();

    return app.exec();
}

分析如下:
前两行是 C++ 的 include 语句,这里我们引入的是QApplication以及QLabel这两个类。

#include <QApplication>
#include <QLabel>

main()函数中第一句是创建一个QApplication类的实例。
对于 Qt 程序来说,main()函数一般以创建 application 对象开始,后面才是实际业务的代码。这个对象用于管理 Qt 程序的生命周期,开启事件循环,这一切都是必不可少的。
(GUI 程序是QApplication,非 GUI 程序是QCoreApplication。QApplication实际上是QCoreApplication的子类。)

QApplication app(argc, argv);

在我们创建了QApplication对象之后,直接创建一个QLabel对象,构造函数赋值“Hello, world”,当然就是能够在QLabel上面显示这行文本。

QLabel label("Hello, world");

最后调用QLabel的show()函数将其显示出来。

label.show();

main()函数最后,调用app.exec(),开启事件循环。我们现在可以简单地将事件循环理解成一段无限循环。正因为如此,我们在栈上构建了QLabel对象,却能够一直显示在那里(试想,如果不是无限循环,main()函数立刻会退出,QLabel对象当然也就直接析构了)。

return app.exec();

若将上面的程序改写成下面的代码,将导致内存泄漏

#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[])
{
    
    
    QApplication app(argc, argv);

    QLabel *label = new QLabel("Hello, world"); //堆区
    label->show();

    return app.exec();
}

当exec()退出时,即窗口关闭,事件循环结束,label 是没有delete 的,这就造成了内存泄露。当然,由于程序结束,操作系统会负责回收内存,所以这个问题不会很严重。即便你这样修改了代码再运行,也不会有任何错误。
由上述代码,我们引出内存的各大区域以及内存泄漏等问题,下面就此问题进行讨论:

二、内存的五大区域

C++程序在执行时,将内存大方向划分为5个区域:
代码区:存放函数体的二进制代码,由操作系统进行管理的
全局区:全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 程序结束后由系统释放
栈区:由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆区:一般由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
文字常量区:常量字符串就是放在这里的。 程序结束后由系统释放。

int a = 0; //全局初始化区 
char *p1; //全局未初始化区 
main() 
{
    
     
	int b; //局部变量,栈区 
	char s[] = "abc"; //字符数组s——局部变量,栈区 ;abc在常量区
	char *p2; //局部变量,栈区
	char *p3 = "123456"; //123456\0在常量区,p3-局部变量,在栈上。 
	static int c =0//全局(静态)初始化区 
	p1 = (char *)malloc(10); 
	p2 = (char *)malloc(20); //分配得来得10和20字节的区域就在堆区。 
    strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 
}

三、堆和栈的理论知识

3.1申请方式

  1. stack:
    由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间

  2. heap:
    需要程序员自己申请,并指明大小,在c语言中使用malloc函数 ,如p1 = (char *)malloc(10);
    在C++中使用new运算符 ,如p2 = new int(10);
    但是注意p1、p2本身是在栈中的。

3.2 申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

堆:首先应该知道操作系统有一个记录空闲内存地址的链表当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序
,另外,对于大多数系统,会在这块 内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的 大小,系统会自动的将多余的那部分重新放入空闲链表中。

3.3申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.

四、内存泄漏

1、内存泄漏的定义
内存泄漏(memory leak)指的是在编写应用程序的时候,程序分配了一块内存,但由于疏忽或错误造成了程序未能释放掉不再使用的内存。即内存被分配出去,但是无法收回,导致其他进程无法使用这块内存,这种情况被定义成内存泄漏。
内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
2、内存泄漏的类型
(1)堆内存泄漏 (Heap leak).堆内存指的是程序运行中根据需要通过malloc、realloc、new等函数从堆中分配一块内存,使用完成后必须调用对应的 free或者delete函数删掉从堆中分配的内存。如果程序的设计的错误导致这部分内存没有被释放,那么此后这块内存将不会被使用,就会产生堆内存泄漏 (Heap leak)。

(2)系统资源泄露(Resource Leak).主要指程序使用系统分配的资源比如 Bitmap、handle 、SOCKET等没有使用相应的函数释放掉,导致系统资源的浪费,严重可导致系统效能降低,系统运行不稳定。

3、内存泄漏解决办法
解决内存泄漏最有效的办法就是使用智能指针(Smart Pointer)。使用智能指针就不用担心这个问题了,因为智能指针可以自动删除分配的内存。智能指针和普通指针类似,只是不需要手动释放指针,而是通过智能指针自己管理内存的释放,这样就不用担心内存泄漏的问题了。

c++提供了auto_ptr、unique_ptr、shared_ptr和weak_ptr这几种智能指针:
(1)shared_ptr共享的智能指针
shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。在最后一个shared_ptr析构的时候,内存才会被释放。

注意事项: 
 1.不要用一个原始指针初始化多个shared_ptr。 
 2.不要再函数实参中创建shared_ptr,在调用函数之前先定义以及初始化它。 
 3.不要将this指针作为shared_ptr返回出来。 
 4.要避免循环引用。

(2)unique_ptr独占的智能指针

 1、Unique_ptr是一个独占的智能指针,他不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另外一个 unique_ptr。
 2、unique_ptr不允许复制,但可以通过函数返回给其他的unique_ptr,还可以通过std::move来转移到其他的unique_ptr,这样它本身就不再 拥有原来指针的所有权了。
 3、如果希望只有一个智能指针管理资源或管理数组就用unique_ptr,如果希望多个智能指针管理同一个资源就用shared_ptr。

(3)weak_ptr弱引用的智能指针
弱引用的智能指针weak_ptr是用来监视shared_ptr的,不会使引用计数加一,它不管理shared_ptr内部的指针,主要是为了监视shared_ptr的生命 周期,更像是shared_ptr的一个助手。

 weak_ptr没有重载运算符*和->,因为它不共享指针,不能操作资源,
 主要是为了通过shared_ptr获得资源的监测权,它的构造不会增加引用计数,
 它的析构不会减少引用计数,纯粹只是作为一个旁观者来监视shared_ptr中关连的资源是否存在。 
 weak_ptr还可以用来返回this指针和解决循环引用的问题。

猜你喜欢

转载自blog.csdn.net/shouchen1/article/details/127543654
今日推荐