对象的生命周期:
全局对象:程序启动时分配,程序结束时销毁
局部自动对象:进入块时分配,离开块时销毁
局部static对象:第一次使用时分配,程序结束时销毁
c++中使用new和delete运算符来动态控制内存。
StringBad::StringBad(const char *s)
{
len=std::strlen(s);
str=new char[len+1];
std::strcpy(str,s);
num_string++;
cout<
new和delete缺点:
如果忘记delete,会引发内存泄漏
如果在还有指针引用内存的情况下delete,使用指针时就会产生非法内存的错误
因此,新的标准库提供了智能指针来帮助程序员管理动态内存
shared_ptr p1;
shared_ptr p2;
make_shared 函数使用传递参数来构造给定类型的对象
shared_ptr p3=make_shared(42);
shared_ptr p4=make_shared(10,‘9’);
shared_ptr p5 = make_shared();//不传递任何参数,对象会进行值初始化。
可以认为每个shared_ptr对象都有一个关联的计数器,通常称作引用计数器。
shared_ptr p=make_shared(10);
make_shared函数在堆上开辟一块动态内存,并将指向该内存的指针包装成智能指针返回给p,这块内存的引用计数为1。(引用计数是对内存而言的)
p是一个局部自动对象,当程序离开块时,p被销毁,引用计数减1。引用计数为0,动态内存被释放。
unique_ptr
一个unique_ptr “独享”它所指向的对象
当unique_ptr被销毁时,它所指向的对象也被销毁
初始化unique_ptr必须采用直接初始化形式
unique_ptr p1;
unique_ptr p2(new int(42));
weak_ptr
weak_ptr指向由一个shared_ptr管理的对象,但是不会影响它的引用计数
当创建一个weak_ptr时,要用一个shraed_ptr来初始化它
auto p = make_shared(42);
weak_ptr wp(p);
由于weak_ptr不影响引用计数,它指向的对象可能不存在,所以不能直接使用weak_ptr访问对象
一种安全的做法是使用lock函数,如果weak_ptr指向的对象存在,lock函数返回一个指向共享对象的 shared_ptr
if(shared_ptr np = wp.lock())
{
}
(1)复制构造函数即将一个对象复制到新创建的对象中。用于初始化过程中。
原型:
Class_name (const Class_name &);
如上的
StringBad(const StringBad &);
(2)何时调用复制构造函数?
新建一个对象并将其初始化同类现有的对象时,复制构造函数否将被调用。
假设motto是一个StringBad对象,则下面的4种声明都调用了复制构造函数。
StringBad ditto(motto);
StringBad ditto = motto;
StringBad ditto = StringBad(motto);//使用复制构造函数生成临时对象,然后进行赋值。
StringBad *pStringBad = new StringBad(motto);//声明使用motto初始化一个匿名对象,并将新对象的地址赋给pString指针。
浅拷贝:直接为数据成员赋值(将值保存在相应的空间里)
#include
#include
using namespace std;
class Test
{
private:
int a;
char *str;
public:
Test(int b, char *s)
{
a=b;
strcpy(str,s); //肇事地点,但不是祸端
}
Test(const Test& C)
{
a=C.a;
strcpy(str,C.str);//肇事地点
}
void show ()
{
cout<
深拷贝:在构造函数中,为指针类型的成员,分配专门的空间,以这条规则构造的复制,称为深复制。
#include
#include
using namespace std;
class Test
{
private:
int a;
char *str;
public:
Test(int b, char *s)
{
a=b;
str=new char[strlen(s)+1];
strcpy(str,s); //上一条语句解决肇事地点
}
Test(const Test& C)
{
a=C.a;
str= new char[strlen(s)+1];
strcpy(str,C.str);//解决了肇事地点
}
~Test()
{
delete []str;
}
void show ()
{
cout<
转载自https://www.cnblogs.com/jhmu063/p/7131997.html
static的作用主要有两种:
第一个作用是限定作用域;第二个作用是保持变量内容持久化;
c语言中static的用法:
1、全局静态变量:
用法:在全局变量前加上关键字static,全局变量就定义成一个全局静态变量。 static int temp;
内存中的位置:静态存储区,在整个程序运行期间一直存在。
初始化:未经初始化的全局静态变量会被自动初始化为0(自动对象的值是任意的,除非他被显式初始化);
作用域:全局静态变量在声明他的文件之外是不可见的,准确地说是从定义之处开始,到文件结尾。
2、局部静态变量:
在局部变量之前加上关键字static,局部变量就成为一个局部静态变量。
内存中的位置:静态存储区
初始化:未经初始化的全局静态变量会被自动初始化为0(自动对象的值是任意的,除非他被显式初始化);
作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域结束。但是当局部静态变量离开作用域后,并没有销毁,而是仍然驻留在内存当中,只不过我们不能再对它进行访问,直到该函数再次被调用,并且值不变;
3、静态函数:
在函数返回类型前加关键字static,函数就定义成静态函数。函数的定义和生命在默认情况下都是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用;
c++中static的用法:
1、类的静态成员:
class A{
private:
static int val;
};
在cpp中必须对他进行初始化,初始化时使用作用域运算符来标明他所属类,其属于该类的所有成员共有,只有一个拷贝;
2、类的静态成员函数:
class A{
private:
static int func(int x);
};
实现的时候也不需要static的修饰,因为static是声明性关键字;类的静态函数是该类的范畴内的全局函数,不能访问类的私有成员,只能访问类的静态成员,不需要类的实例即可调用;实际上,他就是增加了类的访问权限的全局函数;
void A::func(int);
静态成员函数可以继承和覆盖,但无法是虚函数;
3、只在cpp内有效的全局变量:
在cpp文件的全局范围内声明:
static int val = 0;
这个变量的含义是该cpp内有效,但是其他的cpp文件不能访问这个变量;如果有两个cpp文件声明了同名的全局静态变量,那么他们实际上是独立的两个变量;
4、只在cpp内有效的全局函数:
函数的实现使用static修饰,那么这个函数只可在本cpp内使用,不会同其他cpp中的同名函数引起冲突;
warning:不要再头文件中声明static的全局函数,不要在cpp内声明非static的全局函数,如果你要在多个cpp中复用该函数,就把它的声明提到头文件里去,否则cpp内部声明需加上static修饰;