(1)栈内存 VS 堆内存
栈内存的特点:更好的局部性,对象自动销毁
堆内存的特点:运行期动态扩展,需要显式释放
(2)C++ 中通常使用 new 与 delete 来构造、销毁对象
对象的构造分成两步:分配内存与在所分配的内存上构造对象;对象的销毁与之类似
(3)new 的几种常见形式
构造单一对象 / 对象数组
int main()
{
int * y = new int(2);
int * y2 = new int[5]{};
delete[] y2;
}
nothrow new
int main()
{
int * y = new(std::nothrow) int[5]{};
if (y == nullptr) //如果没加std::nothrow会抛出异常,if语句不会被执行
{
//...
}
std::cout << y[2] << std::endl;
delete[] y;
}
placement new
int main()
{
char ch[sizeof(int)];
int * y = new (ch) int(4);
std::cout << *y << std::endl;
}
new auto
int main()
{
int * y = new auto(3);
}
(4)new 与对象对齐
#include
#inclued <new>
struct alignas(256) Str //首地址256的整数倍
{
};
int main()
{
Str * ptr = new Str();
stdd::cout << ptr << std::endl;
}
(5)delete常见用法
销毁单一对象 / 对象数组
placement delete
(6)使用 new 与 delete 的注意事项
根据分配的是单一对象还是数组,采用相应的方式销毁
delete nullptr
不能 delete 一个非 new 返回的内存
同一块内存不能 delete 多次
int main()
{
int * ptr = new int(3);
std::cout << ptr << std::endl;
delete ptr;
ptr = nullptr; //置空之后便可以再次释放
std::cout << ptr << std::endl;
delete ptr;
}
使用 new 与 delete 的问题:内存所有权不清晰,容易产生不销毁,多销毁的情况
(1)C++ 的解决方案:智能指针
auto_ptr ( C++17 删除)
shared_ptr / uniuqe_ptr / weak_ptr
(2)shared_ptr——基于引用计数的共享内存解决方案
1)基本用法
#include
#include
#include
int main()
{
//int * x = new int(3);
std::shared_ptr<int> x(new int(3));
std::cout << x.use_count() << std::endl; //引用计数
std::shared_ptr<int> y = x;
std::cout << y.use_count() << std::endl;
std::cout << x.use_count() << std::endl;
}
#include
#include
#include
std::shared_ptr<int> fun()
{
std::shared_ptr<int> res(new int(100));
return res;
}
int main()
{
auto y = fun();
}
2)reset / get 方法
#include
#include
#include
std::shared_ptr<int> fun()
{
std::shared_ptr<int> res(new int(100));
return res;
}
void fun2(int *)
{
}
int main()
{
auto y = fun();
std::cout << *(y.get()) << std::endl; //y.get()返回值为int*
//*(y.get())为int*解引用而不是对智能指针解引用
fun2(y.get());
}
#include
#include
#include
std::shared_ptr<int> fun()
{
std::shared_ptr<int> res(new int(100));
return res;
}
int main()
{
auto y = fun();
y.reset(new int(3));
}
3)指定内存回收逻辑
4)std::make_shared(将int(3)与引用计数的内存位置放的尽量近)
#include
#include
#include
int main()
{
std::shared_ptr<int> ptr(new int(3));
//std::shared_ptr ptr2 = std::make_shared(3);
auto ptr2 = std::make_shared<int>(3);
}
4)支持数组( C++17 支持 shared_ptr ; C++20 支持 make_shared 分配数组)
#include
#include
#include
int main()
{
std::shared_ptr<int[]> ptr(new int[5]); //C++17
auto ptr2 = std::make_shared<int[]>(5); //C++20
}
5)注意: shared_ptr 管理的对象不要调用 delete 销毁
#include
#include
#include
int main()
{
std::shared_ptr<int> x(new int(5));
//delete x.get(); //程序会崩溃,因为重复释放
//std::shared_ptr y(x.get()); //引用计数没有传给y,也会重复释放
}
(3)unique_ptr——独占内存的解决方案
1)基本用法
#include
#include
#include
int main()
{
std::unique_ptr<int> x(new int(5));
}
2)unique_ptr 不支持复制,但可以移动
#include
#include
#include
int main()
{
std::unique_ptr<int> x(new int(5));
std::cout << x.get() << std::endl;
std::unique_ptr<int> y = std::move(x);
std::cout << x.get() << std::endl;
std::cout << y.get() << std::endl;
}
#include
#include
#include
std::unique_ptr<int> fun()
{
std::unique_ptr<int> res(new int(5));
return res;
}
int main()
{
std::unique_ptr<int> x = fun();
}
(4)weak_ptr——防止循环引用而引入的智能指针
循环引用
#include
#include
#include
struct Str
{
std::shared_ptr<Str> m_nei;
~Str()
{
std::cout << "~Str() is called!\n";
}
};
int main()
{
std::shared_ptr<Str> x(new Str{}); //[x] = 1
std::shared_ptr<Str> y(new Str{}); //[y] = 1
x->m_nei = y; //[y] = 2
y->m_nei = x; //[x] = 2
}
(1)基于 shared_ptr 构造
#include
#include
#include
struct Str
{
std::weak_ptr<Str> m_nei;
~Str()
{
std::cout << "~Str() is called!\n";
}
};
int main()
{
//[]表示引用计数
std::shared_ptr<Str> x(new Str{}); //[x] = 1
std::shared_ptr<Str> y(new Str{}); //[y] = 1
x->m_nei = y; //[y] = 1
y->m_nei = x; //[x] = 1
}
(2)lock方法
#include
#include
#include
struct Str
{
std::weak_ptr<Str> m_nei;
~Str()
{
std::cout << "~Str() is called!\n";
}
};
int main()
{
//[]表示引用计数
std::shared_ptr<Str> x(new Str{}); //[x] = 1
std::shared_ptr<Str> y(new Str{}); //[y] = 1
x->m_nei = y; //[y] = 1
y->m_nei = x; //[x] = 1
if (auto ptr = x->m_nei.lock(); ptr)
{
std::cout << "Can access pointer\n";
}
else
{
std::cout << "Cannot access pointer\n";
}
}
(1)sizeof 不会返回动态分配的内存大小
(2)使用分配器( allocator )来分配内存(推荐)
#include
#include
#include
#include
int main()
{
std::allocator<int> al;
int * ptr = al.allocate(3); //分配了3个int的内存
al.deallocate(ptr, 3); //释放内存
}
(3)使用 malloc / free 来管理内存(C)
(4)使用 aligned_alloc 来分配对齐内存(C)
(5)动态内存与异常安全
(6)C++ 对于垃圾回收的