new变量,动态分配,堆分配,需delete释放。
int *pi = new int; //未定义
int *pi2 = new int();//初始化0
int *pi3 = new int(100);
string *ps = new string;//断点调试发现""
string *ps2 = new string();//""
vector<int> *pv = new vector<int>{1, 2, 3};
class A {
public:
A() {
cout <<"A()" <<endl;
}
int m_i;
};
//自定义类,两者等价
A *p1 = new A;
A *p2 = new A();
string* ps2 = new string(5, 'a');
string** ps3 = new (string *)(ps2);
//auto ps3 = new auto(ps2);//与上面等价
delete ps2;
delete ps3;
const int *pi = new const int(200);//new后面const可省略
//*pi = 300;//错误
delete pi;//可以delete const对象
通过创建MFC应用项目来观察内存泄漏。
class A {
public:
A(){cout<<"A()"<<endl;}
~A(){cout<<"~A()"<<endl;}
};
A* pa = new A(); //调用构造函数
delete pa;//调用析构函数
void *p=operator new(100);//分配100各字节,malloc?
new运算符做了两件事:分配内存(通过调用operator new(…)),调用构造函数初始化该内存。
delete运算符做了两件事:调用析构函数,释放内存(通过调用operator delete(…))。
int *p=new int;//分配4个字节
delete p;
//new内部有记录机制,记录分配字节数,用于delete时回收
A *pA=new A[2](); //会多分配4个字节,专门保存数组大小
delete[] pA;//delete[]时,取出数组大小,调用多次析构函数
delete与delete[],调用析构函数次数不同,释放内存大小不同(多分配4个字节)。
new对象返回的对象指针称为裸指针(无包装)。
智能指针对裸指针进行了包装,能够自动释放所指向的对象,管理动态分配的new对象的生命周期,有效防止内存泄漏。
三种智能指针都是类模板(使用<>):
shared_ptr
共享式指针,多个指针指向同一个对象,最后一个指针销毁时,对象被释放。
weak_ptr
辅助shared_ptr工作。
unique_ptr(完全取代auto_ptr)
独占式指针,同一时间只有一个指针指向该对象,对象所有权可以移交出去。
对象被多个shared_ptr共享,使用引用计数工作,最后一个指向该对象的指针被析构或者指向其它对象时,该对象被释放。
shared_ptr<string> p;
shared_ptr<int> pi(new int(100));
//错误,智能指针explicit,禁止隐式类型转换
shared_ptr<int> pi2 = new int(100);
shared_ptr<int> makes(int value) {
//return new int(value);//错误,int*与shared_ptr不等
return shared_ptr<int>(new int(value));
}
int *pi = new int;
//不推荐
//shared_ptr p1(pi);
shared_ptr<int> p1(new int);
shared_ptr<int> p2 = std::make_shared<int>(100);
//make_shared后面参数需与string里某个构造函数匹配
shared_ptr<string> p3 = std::make_shared<string>(5, 'a');
shared_ptr<int> p4 = std::make_shared<int>();//0
p4 = std::make_shared<int>(400);//p4释放刚才的对象,重新指向新对象
auto p5 = std::make_shared<string>(5, 'a');
auto p6=std::make_shared<int>(100);
auto p7(p6);//或者auto p7=p6;
//两个引用计数
void myfunc(shared_ptr<int> ptmp){
//实参传递会增加,引用传递不增加
return;//退出函数,引用不变
}
make_shared<int> myfunc2(shared_ptr<int> &ptmp){
//引用传递不增加
return ptmp;
}
myfunc2(p7); //无接收变量,引用不增加
auto p8=myfunc2(p7); //有接收变量,引用+1
p8=std::make_shared<int>(100);//p8指向新对象计数1,p6、p7计数恢复2
p7=std::make_shared<int>(200);//p7指向新对象计数1,p6计数恢复2
p6=std::make_shared<int>(300);//p6指向新对象计数1,p6指向原对象内存被释放
p8=p7;//p7指向对象计数2,p8指向原对象内存被释放
shared_ptr<int> myp(new int(100));
int icount=myp.use_count();//1
shared_ptr<int> myp2(myp);
icount=myp.use_count();//2
shared_ptr<int> myp3;
myp3=myp2;
icount=myp.use_count();//3
icount=myp3.use_count();//3
shared_ptr<int> myp(new int(100));
if(myp.unique())
cout<<"unique\n";
shared_ptr<int> myp2(myp);
if(myp.unique())
cout<<"unique\n";
shared_ptr<int> p(new int(100));
p.reset();
if(p==nullptr)
cout<<"empty"<<end;
(2)带参数(一般new指针)
原指向对象引用参数减1(为0则释放空间),同时智能指针指向新分配对象。
shared_ptr<int> pi(new int(100));
auto pi2(pi);
pi.reset(new int(100));
shared_ptr<int> p(new int(100));
char buf[256];
sprintf(buf, sizeof(buf), "%d", *p);
shared_ptr<int> myp(new int(100));
int* p=myp.get();
*p=34;
shared_ptr<string> p1(new string("str1"));
shared_ptr<string> p2(new string("str2"));
std::swap(p1, p2);
p1.swap(p2);
shared_ptr<string> p1(new string("str1"));
p1=nullptr;
shared_ptr<string> p1(new string("str1"));
if(p1)
cout<<*p1<<end;
void myDeleter(int *p){
delete p;
}
shared_ptr<int> p(new int(100), myDeleter);
p.reset();
shared_ptr<int> p(new int(100), [](int *p){
delete p;
});
p.reset();
shared_ptr<int> p(new int[8], [](int *p){
delete[] p;
});
p.reset();
//或者
shared_ptr<int[]> p(new int[8]);
class A {
public:
A(){cout<<"A()\n";}
~A(){cout<<"~A()\n";}
};
shared_ptr<A> pA(new A[8], [](A *p){
delete[] p;
});
p.reset();
//或者
shared_ptr<A> pA(new A[8], std::default_delete<A[]>());
shared_ptr<A[]> pA(new A[8]);
自己写模板封装shared_ptr数组
template<typename T>
shared_ptr<T> make_shared_array(size_t size) {
return shared_ptr<T> (new T[size], std::default_delete<T[]>());
}
shared_ptr<int> p = make_shared_array<int>(5);
shared_ptr<A> pA = make_shared_array<A>(5);
(2)额外说明
shared_ptr指定删除器不同,但指向对象相同,这两个shared_ptr属于同一个类型。
auto lambda1 = [](int *p) {delete p;};
auto lambda2 = [](int *p) {delete p;};
shared_ptr<int> p1(new int(100), lambda1);
shared_ptr<int> p2(new int(200), lambda2);
p2 = p1;
//先调用lambda2释放p2指向对象,然后p2指向p1所指对象。
//最后lambda1释放p1、p2共同指向对象。
vector<shared_ptr<int>> pvec{p1, p2};
weak_ptr绑定到shared_ptr上并不改变shared_ptr的引用计数。
weak_ptr,能力弱(弱共享/弱引用,共享其它shared_ptr指向的对象),控制不了所指向对象的生成期。
弱引用,用来监视强引用(shared_ptr)的生命周期(能监视到指向对象是否存在),是shared_ptr的助手(旁观者)。
auto pi = make_shared<int>(100);
weak_ptr<int> piw(pi);
weak_ptr<int> piw2;
piw2=piw;
//不能使用weak_ptr直接访问对象。
//lock()返回shared_ptr,可判断指向对象是否存在(nullptr)
auto pi2=piw.lock();
if(pi2)
cout<<"exists";
auto pi = make_shared<int>(100);
auto pi2(pi);
weak_ptr<int> piw(pi);
int isc = piw.use_count(); //2
pi.reset();
pi2.reset();
if(piw.expired())
cout<<"empty";
auto pi = make_shared<int>(100);
weak_ptr<int> piw(pi);
piw.reset();
auto pi = make_shared<int>(100);
weak_ptr<int> piw;
pw=pi;
if(!pw.expired()) {
auto p2 = pw.lock();
if(p2 != nullptr)
cout<<"exist";
}
weak_ptr<int> piw;
{
auto pi = make_shared<int>(100);
pw=pi;
}
if(pw.expired()) {
cout<<"empty";
}
weak_ptr|shared_ptr的尺寸(sizeof)是裸指针的2倍。
shared_ptr<int> p(new int(100));
weak_ptr<int> pw(p);
sizeof(int *); //4,x86
sizeof(p); //8,x86
sizeof(pw); //8,x86
包含两个裸指针:
(1)指向智能指针所指向的对象。
(2)指向数据结构(控制块,shared_ptr创建),里面包含:
shared_ptr<int> myfunc(int value) {
return make_shared<int>(value);
}
auto p = myfunc(12);
void proc(shared_ptr<int> ptr){
return;
}
int *p=new int(100);
//proc(p);//int*不能转换为shared_ptr
proc(shared_ptr<int>(p));//离开proc后,p指向内存已被释放。
*p=45;//error
//修改为
shared_ptr<int> p(new int(100));
proc(p);
*p=45;
int *p=new int(100);
//p指向内存释放两次,error
shared_ptr<int> p1(p);
shared_ptr<int> p2(p);
//改为
shared_ptr<int> p1(new int(1));
shared_ptr<int> p2(new int(1));
shared_ptr<int> myp(new int(1));
int *p=myp.get();
//delete p;//error
{
//shared_ptr myp2(p); //error
shared_ptr<int> myp2(myp);
}
class CT {
public:
shared_ptr<CT> getself() {
return shared_ptr<CT>(this);
}
};
shared_ptr<CT> p1(new CT);
shared_ptr<CT> p2 = p1; //ok,两个强引用
shared_ptr<CT> p3 = p1->getself();//error,同一个指针this构造了两个无关联的智能指针,会释放两次
//enable_shared_from_this,类模板
class CT:public std::enable_shared_from_this<CT> {
public:
shared_ptr<CT> getself() {
//return shared_ptr(this);
return shared_from_this();
}
};
shared_from_this工作原理:
enable_shared_from_this是类模板,类型模板参数是继承的子类的类名,该类模板中有一个弱指针weak_ptr(观测this),调用shared_from_this方法实际是调用weak_ptr的lock方法,返回shared_ptr。
class CA;
class CB;
class CA {
public:
shared_ptr<CB> m_pbs;
~CA() {
cout<<"~CA()"<<endl;
}
};
class CB {
public:
shared_ptr<CA> m_pas;
~CB() {
cout<<"~CB()"<<endl;
}
};
shared_ptr<CA> pca(new CA);
shared_ptr<CB> pcb(new CB);
pca->m_pbs = pcb;
pcb->m_pas = pca;
//CA,CB对象有两个引用计数,离开作用域后变成1个,不会被释放,内存泄漏。
//修改CA或CB中成员变量为weak_ptr
class CA;
class CB;
class CA {
public:
shared_ptr<CB> m_pbs;
~CA() {
cout<<"~CA()"<<endl;
}
};
class CB {
public:
weak_ptr<CA> m_pas;
~CB() {
cout<<"~CB()"<<endl;
}
};
shared_ptr<CA> pca(new CA);
shared_ptr<CB> pcb(new CB);
pca->m_pbs = pcb;//CB两个强引用
pcb->m_pas = pca;//CA一个强引用
//先执行CA类析构函数(释放CA中一个CB强引用),后执行CB类析构函数(CA类不释放,CB类强引用不可能为0)
1.尺寸问题
shared_ptr创建控制块的时机:
(1)make_shared分配并初始化一个对象时。
shared_ptr<int> p=std::make_shared<int>(100);
(2) 指针创建shared_ptr对象时。
int *pi=new int;
shared_ptr<int> p(pi);
//或者
shared_ptr<int> p(new int);
2.移动语义
shared_ptr<int> p1(new int(1));
shared_ptr<int> p2(std::move(p1));//p1空,引用计数1
shared_ptr<int> p3;
p3 = std::move(p2);//p2空,引用计数1
复制使shared_ptr的引用计数递增,移动不会使shared_ptr的引用计数递增。
shared_ptr可以提供删除器和分配器(解决内存分布问题,保存在控制块中)。
shared_ptr<int> p(new int(), myDeleter(), myMallocator<int>());
优先使用make_shared构造智能指针,编译器内部会有针对内存分配的特殊处理,使make_shared效率更高,如消除重复代码、改进安全性等。
shared_ptr<string> p1(new string("hello"));
//至少分配两次内存
//构造string实例分配内存
//shared_ptr构造函数中shared_ptr控制块分配内存
独占式智能指针,专属所有权,同一时刻,智能指针。
unique_ptr<int> pi(new int(15));
auto p2(new int(15));//此时p2为int*
unique_ptr<int> p1 = std::make_unique<int>(15);
auto p2 = std::make_unique<int>(200);
auto ps1 = std::make_unique<string>("hello");
unique_ptr<string> ps2(ps1); //error
unique_ptr<string> ps3 = ps1; //error
unique_ptr<string> ps4;
ps4 = ps1; //error
auto ps1 = std::make_unique<string>("hello");
unique_ptr<string> ps4;
ps4 = std::move(ps1); //ok
unique_ptr<string> ps1(new string("hello"));
unique_ptr<string> ps2(ps1.release());
if(ps1 == nullptr)
cout<<"ps1 release()"<<endl;
//ps2.release();//会导致内存泄漏
string *tmp = ps2.release();
delete tmp;
unique_ptr<string> ps1(new string("hello"));
ps1.reset();//释放ps1指向对象,并将ps1置空
if(ps1 == nullptr)
cout<<"ps1 reset()"<<endl;
unique_ptr<string> ps1(new string("hello"));
unique_ptr<string> ps2(new string("hello2"));
ps2.reset(ps1.release());//释放ps2指向内存,并重新指向ps1指向的内存,同时ps1被置空
ps2.reset(new string("hello2"));//释放ps2指向内存,并重新指向新分配的内存
unique_ptr<string> ps1(new string("hello"));
ps1 = nullptr;//释放ps1指向内存,同时ps1被置空
std::unique_ptr<int[]> ptrarray(new int[10]);
ptrarray[0] = 12;
ptrarray[1] = 24;
ptrarray[9] = 124;
class A{
public:
A(){}
~A(){}
};
//error
//std::unique_ptr ptrarray(new A[10]);
//自己的删除器
auto mydel = [](A* p) {
delete[] p;
};
std::unique_ptr<A, decltype(mydel)> ptrarray2(new A[10], mydel);
std::unique_ptr<A[]> ptrarray(new A[10]);
unique_ptr<string> ps1(new string("hello"));
string *ps = ps1.get();
const char *p1 = ps->c_str();
*ps="new string";
const char *p2 = ps->c_str();
//p1和p2指向不同的内存地址
unique_ptr<string> ps1(new string("hello"));
*ps1="new string";
unique_ptr<string> ps1(new string("hello"));
unique_ptr<string> ps2(new string("hello2"));
std::swap(ps1, ps2);
ps1.swap(ps2);
unique_ptr<string> ps1(new string("hello"));
if(ps1)
cout<<"point"<<endl;
auto myfunc(){
return unique_ptr<string>(new string("hello")); //右值
}
shared_ptr<string> ps1 = myfunc();
unique_ptr<string> ps(new string("hello"));
shared_ptr<string> ps2 = std::move(ps);
unique_ptr不能被复制,将要被销毁时,可以被复制。
unique_ptr<string> myfunc(){
unique_ptr<string> pr(new string("hello"));
return pr;
//return unique_ptr(new string("hello"));
}
unique_ptr<string> ps;
ps = myfunc();
unique_ptr<指向的对象类型,删除器> 智能指针变量名;
//删除器就是可调用对象
void mydeleter(string *pdel){
delete pdel;
pdel = nullptr;
}
typedef void(*fp)(string *);
unique_ptr<string, fp> ps(new string("hello"), mydeleter);
using fp = void(*)(string *);
unique_ptr<string, fp> ps(new string("hello"), mydeleter);
//decltype返回函数类型,*表示函数指针类型
//fp是void *(string *)
typedef decltype(mydeleter)* fp;
unique_ptr<string, fp> ps(new string("hello"), mydeleter);
unique_ptr<string, decltype(mydeleter)*> ps(new string("hello"), mydeleter);
auto mydella = [](string *pdel){
delete pdel;
pdel = nullptr;
}
unique_ptr<string, decltype(mydella)> ps(new string("hello"), mydella);
share_ptr指定删除器不同,但指向对象相同,属于同一个类型,可放在同一个容器内。
unique_ptr指定删除器不同,类型不同,不能放在同一个容器内。
unique_ptr一般和裸指针一样,lambda表达式删除器,尺寸不会变;函数删除器,尺寸会变化。
string *p;
sizeof(p);//4
unique_ptr<string> ps(new string("hello"));
sizeof(ps)//4
void myfunc(){
//string *ps=new string("hello");
unique_str<string> ps(string("hello"));
//...
if(true){
//delete ps;
return;
}
//delete ps;
return;
}
shared<string> ps(string("hello"));
shared<string> ps2=ps;
unique_ptr<string> ps(new string("hello"));
//unique_ptr ps2=ps;//error
//unique_ptr ps2(ps);//error
unique_ptr<string> ps2=std::move(ps);