以下知识和部分代码学习自Light-City/CPlusPlusThings: C++那些事 (github.com)
栈
c++
class Obj{
public:
Obj()=default;
~Obj()=default;
};
//栈:自动管理内存
void stack_example()
{
Obj s; //栈上创建对象
//离开作用域后自动销毁
}
堆
c++
class Obj{
public:
Obj()=default;
~Obj()=default;
};
void heap_exmaple()
{
Obj* s=new Obj(); //堆上创建对象
//同时如果这里抛出异常,后面的delete不会执行
delete s;//需要手动删除
}
从以上例子看出栈和堆的内存分配方式完全不同,栈会自动分配和释放,不会发生内存泄漏。而堆要求我们 手动管理,无论是忘记加delete,还是抛出异常,都会造成内存泄漏。
RALL:资源获取即初始化
总的来说RALL即:
1,资源在构造函数中获得
2,资源在析构函数中释放
3,类的实例由堆栈控制
一下是代码演示:
c++
#include <iostream>
#include <mutex>
#include <fstream>
using namespace std;
// RAII 资源获取即初始化,例1
enum class shape_type {
circle,
triangle,
rectangle,
};
class shape {
public:
shape() { cout << "shape" << endl; }
virtual void print() {
cout << "I am shape" << endl;
}
virtual ~shape() {}
};
class circle : public shape {
public:
circle() { cout << "circle" << endl; }
void print() {
cout << "I am circle" << endl;
}
};
class triangle : public shape {
public:
triangle() { cout << "triangle" << endl; }
void print() {
cout << "I am triangle" << endl;
}
};
class rectangle : public shape {
public:
rectangle() { cout << "rectangle" << endl; }
void print() {
cout << "I am rectangle" << endl;
}
};
shape *create_shape(shape_type type) {
switch (type) {
case shape_type::circle:
return new circle();
case shape_type::triangle:
return new triangle();
case shape_type::rectangle:
return new rectangle();
}
}
class shape_wrapper {
public:
explicit shape_wrapper(shape *ptr = nullptr) : ptr_(ptr) {}
~shape_wrapper() {
delete ptr_;
}
shape *get() const {
return ptr_;
}
private:
shape *ptr_;
};
void foo() {
shape_wrapper ptr(create_shape(shape_type::circle));
ptr.get()->print();
}
int main() {
// 第一种方式
shape *sp = create_shape(shape_type::circle);
sp->print();
delete sp;
// 第二种方式 RAII
foo();
return 0;
}
对象切片问题
这个问题是我在刚接触c++时非常容易犯得错误,即把一个派生类对象直接赋值给一个基类对象。
c++
int main() {
circle object;
shape sp = object;
sp.print();
return 0;
}
此时结果如下:
c++
shape
circle
I am shape
简单来说派生类"多出来"的部分被切掉了,只剩下基类部分。因此我们永远不要通过值传递将派生类传递给基类,而要使用指针和引用。
智能指针
c++11后引入了智能指针,如unique_ptr,shared_ptr。使用智能指针不仅可以解决堆内存需要手动分配的问题和对象切片问题,还能使代码更加优雅简洁。所以请毫不犹豫使用智能指针。