安静学习

static关键字

内存

静态变量和全局变量一起存储在静态数据段,其中初始化的变量存储在DATA段,未初始化的变量存储在BSS段,程序开始运行时会将BSS段的内容置零。因此可以直接使用未初始化的静态变量(其值为0)。

静态变量初始化时间

全局静态变量应该是在程序运行之前初始化,而C++中,初始化必须执行构造函数才行,所以局部静态变量应该是在第一次实例化对象时初始化。(待求证)

动机

需要某个变量拥有局部变量的作用域但要有全局变量的生命周期,即其不能随着函数的返回而消失,静态变量出现了。

diff

局部静态变量与局部变量:静态变量生命周期变长
全局静态变量与全局变量:静态变量无法被外连接,即其它文件无法通过extern声明获得静态变量的访问权。

静态函数

限制外连接性

静态成员函数

无this指针,可以直接通过类访问(A::foo()),也可以通过对象访问(a.foo()),但是通过对象访问时由于没有传递this指针,因此并不会与具体的对象绑定。因此静态成员函数一般是用来访问静态数据成员的,并不会访问非静态数据成员。还有一个原因是静态成员()会在非静态成员存在之前存在,因此不能访问。在VS2015中键入代码会直接提醒非静态成员变量需要与特定对象绑相对。

优点

数据共享,节省空间

C++和C的区别

C++是面向对象的语言,C是面向过程的结构化语言;
C++具有封装、继承、多态三种特性;
C++支持范式编程,比如模板类,函数模板。

C++中4种cast转换

static_cast

隐式类型转换

int a=1;
double d=static_cast<double>(a);

还可以用于多态向上转换,向下转能成功但是安全性未知(dynamic_cast能执行安全向下转型)

class B{};
class D:public B{void foo(){cout<<D::foo<<endl;}};
int main(){
	D* pd=new D;
	B* pb=static_cast<B*> pd;
	return 0;
}

const_cast

取消常量性

int main() {
	int j = 0;
	const int i = j;
	int &k = const_cast<int &>(i);
	++k;
	cout << i << endl;

	string a = "123";
	char *p = const_cast<char *>(a.c_str());
	strcpy_s(p,4, "abc");
	cout << a.c_str() << endl;

	return 0;
}

dynamic_cast

用于多态类型转换,可以完成安全向下转型,只能用于含有虚函数的类,只能转指针或引用。向下转化失败时,对于指针返回nullptr,对于引用抛异常。

reinterpret_cast

重新解释数据

int a=1;
char *p=reinterpret_cast<char *>(a);//error ,int *类型的值不能用于初始化char *类型的实体
int *p=reinterpret_cast<int *>(a);	
cout<<"*p"<<endl;
//编译通过,运行时出错,指针访问未知内存

指针和引用

引用的底层实现是指针。用起来的差别:
指针是一个独立的标变量,可以再赋值。引用只是一个变量的别名,初始化后不能再改变
sizeof(指针)=4/8(操作系统地址位数);sizeof(引用)=sizeof(变量)
传指针时还是会产生临时指针变量,传引用则不会
指针可以有多级指针,而引用只有一级
指针和引用使用++运算符的意义不一样
如果返回动态内存分配的对象或内存,必须使用指针,引用可能引起内存泄露(待求证)

指针和数组

指针存放的是地址,指向数据,数组直接存储数据,拥有数据的拷贝

智能指针

智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄露。C++11中最常用的智能指针类型为shared_ptr,它采用引用计数的方法,记录当前内存资源被多少个智能指针引用。该引用计数的内存在堆上分配。当新增一个时引用计数加1,当过期时引用计数减1。当引用计数为0时,调用析构函数,释放引用的内存资源。若是循环引用则引用计数无法减到0,造成内存泄露。使用weak_ptr解决这个问题。对shared_ptr进行初始化时不能将一个普通指针直接赋值给智能指针,因为一个是指针,一个是类。可以通过make_shared函数或者通过构造函数传入普通指针。并可以通过get函数获得普通指针。

auto_ptr

C++11已经抛弃

auto_ptr<string> p1(new string("Hellow World!"));
auto_ptr<string> p2;
p2=p1;

此时不会报错,p2剥夺了p1的所有权,但是当程序运行时访问p1将会报错,此时p1=nullptr.

unique_ptr

unique_ptr<string> p1(new string("Hellow World!"));
unique_ptr<string> p2;
p2=p1;//编译报错

unique_ptr<string> p3;
p3=unique_ptr<string>(new string("You"));//allowed

//move()
p2=move(p1); //allowed

shared_ptr

带引用计数的智能指针

weak_ptr

作用:防止shared_ptr循环引用
它指向一个shared_ptr管理的对象。进行该对象的内存管理的还是那个shared_ptr。weak_ptr只是提供了对被管理对象的一个访问手段,它的构造和析构不会引起引用计数的改变,和shared_ptr可以相互转化,shared_ptr可以直接复制给它,它可以通过调用lock函数来获得shared_ptr。

class B;
class A {
public:
	shared_ptr<B> pb_;
	~A() {
		cout << "delete A" << endl;
	}
};
class B {
public:
	shared_ptr<A> pa_;
	~B() {
		cout << "delete B" << endl;
	}

};
void foo() {
	shared_ptr<B> pb(new B);
	shared_ptr<A> pa(new A);
	pb->pa_ = pa;
	pa->pb_ = pb;
	cout << pb.use_count() << endl;
	cout << pa.use_count() << endl;
}

int main() {
	foo();
	return 0;
}

循环引用,函数退出时,AB都没有析构,将其中一个shared_ptr改成weak_ptr即可成功析构。

为什么构造函数不能是虚函数

因为虚函数必须通过虚函数指针找到虚函数表才行,而虚函数指针是在对象的内存空间中,必须调用构造函数构造出对象才有内存空间,死锁了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值