关于栈的底层知识可以看看堆和栈
栈的基础原理
每次在C++中进入一个作用域,其实是在Push栈帧到栈中,而作用域结束后,对应的栈帧则会Push出栈,其中基于栈声明的变量和栈帧中创建的对象都会随之消散。
INFO
栈就像日常生活中,在桌子上一本一本向上堆积的书本,你每次只能从最顶上放置书本或者取走书本,每次取走书本后,会将其丢弃,在书籍中的内容也会随之消失。
作用域是指由{}包裹的代码,往往有类作用域、函数作用域和空作用域等
class Entity
{
public:
Entity()
{
std::cout << "创建对象" << std::endl;
}
~Entity()
{
std::cout << "销毁对象" << std::endl;
}
}
int main()
{
{
Entity e_statck; //e_stack在栈中创建
Entity* e_heap = new Entity(); //e_heap在堆中创建
}
//当运行到此时,上面声明的对象e_stack的作用域已经结束,
//因此在栈中创建的e_stack随着作用域一起结束并销毁
//而堆中创建的e_heap仍可以继续存活
}栈对象的使用方法
int* createArray()
{
//下面代码创建一个整型数组并返回数组指针
//但是该指针指向的内容会随着函数调用结束而销毁
//最终得到错误的内容
int array[50];
return array;
}
void createArray(int* array)
{
//相关操作
//避免创建局部变量指针
}
int main()
{
int* a = createArray();
}在实际代码开发过程中应避免出现,在局部创建变量后返回对应指针的做法,这会导致意料之外的结果。
在代码开发过程中我们可以利用这个特性,帮助我们自动化处理代码。例如作用域指针或者作用域锁。
作用域指针
作用域指针是一个类,对于指针的一个包装器,在构造时使用堆分配指针,然后在析构时删除指针,因此我们可以自动化该类的new和delete
class Entity
{
public:
Entity()
{
std::cout << "创建对象" << std::endl;
}
~Entity()
{
std::cout << "销毁对象" << std::endl;
}
}
//创建了一个最基本的作用域指针
class ScopedPtr
{
private:
Entity* m_Ptr;
public:
ScopedPtr(Entity* ptr)
: m_Ptr(ptr)
{
}
~ScopedPtr()
{
delete m_Ptr;
}
}
int main()
{
{
//e_heap在堆中创建,需要手动使用delete进行销毁
Entity* e_heap = new Entity();
//e_ptr可以自动销毁指针和对象
ScopedPtr e_ptr = new Entity();
}
//超出作用域时,e_ptr作为局部变量会调用析构函数
//析构时使用delete销毁在堆上创建的entity对象
//析构结束的同时销毁类中的属性m_ptr指针和e_ptr变量
}上述的 ScopedPtr 就是智能指针中实现的基础功能,利用这种自动构造,离开作用域时自动析构的特性,可以在许多场景中进行利用。例如制作一个计时器类,在构造时开始计时,在析构时停止计时并输出两个时间差,那么在作用域开始阶段声明后可以得到整个作用域的执行时间,不需要人为的去停止。此外在自动作用域锁方面,可以在函数开头进行声明进行上锁,然后在函数执行完后自动解锁