1、new delete与malloc free区别
1、 new delete是运算符,malloc free是函数。
2、 前者不需要传入大小,后者需要。
3、 前者会调用构造、析构函数,后者不会。
4、 前者不需要强制转换,后者需要。
2、智能指针
智能指针是避免忘记释放动态申请对象容易内存泄漏而设计的。主要特点是会在离开作用域会使用delete进行内存释放。实现原理也就是在构造函数中new对象,析构函数中delete对象。智能指针有share_ptr、auto_ptr、unique_ptr、weak_ptr。
auto_ptr,当使用拷贝或赋值构造函数时会将右值赋值给左值后将右值指针置零,局限性就在赋值后不能使用。
unique_ptr,在auto_ptr的基础上直接禁用赋值和拷贝构造函数,这样从根本上解决了问题,但是赋值时会比较麻烦。
其中shared_ptr中有一个引用计数,用于记录多少个对象指向动态对象,析构对象时计数值减1,为0时候再释放动态内存。避免了重复释放的问题。但是会引出循环引用的问题:创建出来的两个对象通过shared_ptr相互指的时候析构时由于被别的对象指向所以计数值不为0,导致无法调用析构函数释放内存。解决办法是创建时使用shared_ptr,引用时使用weak_ptr。
shared_ptr实现原理(理解基本原理,细节没有处理):主要是重载->*=运算符,在=运算符中对当前对象释放(因为接下来该指针不指向它了,所以计数值-1,指向具体有没有释放还要根据计数值决定),然后指向新的对象,并将新的对象中的计数加1.
#include <iostream>
#include <memory>
using namespace std;
class boy;
class girl;
template<typename T>
class my_shared_ptr
{
public:
my_shared_ptr(T *a)
{
ref_cnt = 1;
Type_Ptr = a;
}
my_shared_ptr(T &a)
{
ref_cnt = 1;
Type_Ptr = &a;
}
my_shared_ptr()
{
ref_cnt = 1;
Type_Ptr = NULL;
}
void Release()
{
if(Type_Ptr&&((--ref_cnt) == 0))
{
delete Type_Ptr;
Type_Ptr = NULL;
}
}
~my_shared_ptr()
{
Release();
}
T* operator->()
{
return Type_Ptr;
}
T& operator*()
{
return *Type_Ptr;
}
my_shared_ptr& operator=(my_shared_ptr &target)
{
if(this != &target)
{
Release();
Type_Ptr = target.Type_Ptr;
ref_cnt = target.ref_cnt;
target.Ref_Add();
}
return *this;
}
void Ref_Add()
{
ref_cnt++;
}
private:
T *Type_Ptr;
int ref_cnt;
};
// 男孩类
class boy {
public:
boy() { cout << "boy structure" << endl; }
~boy() { cout << "~boy destruct" << endl; }
void set_girl_friend(my_shared_ptr<girl>& g) {
girl_friend = g;
}
private:
my_shared_ptr<girl> girl_friend;
};
// 女孩类
class girl {
public:
girl() { cout << "girl structure" << endl; }
~girl() { cout << "~girl destruct" << endl; }
void set_boy_friend(my_shared_ptr<boy>& b) {
boy_friend = b;
}
private:
my_shared_ptr<boy> boy_friend;
};
// 测试函数
void test() {
// 定义共享指针,初始化指向新建的girl女孩类
my_shared_ptr<girl> sp_girl(new girl());
// 定义共享指针,初始化指向新建的boy男孩类
my_shared_ptr<boy> sp_boy (new boy());
// 调用 sp_girl 指向 girl 的成员函数 set_boy_friend
// 将 sp_boy 共享指针作为参数传递进成员函数
sp_girl->set_boy_friend(sp_boy);
// 调用 sp_boy 指向 boy 的成员函数 set_girl_friend
// 将 sp_girl共享指针作为参数传递进成员函数
sp_boy->set_girl_friend(sp_girl);
}
int main(void) {
// 调用测试函数
test();
return 0;
}
weak_ptr,不能改变引用计数,只能观察对象,不能直接使用*和->访问对象,需要通过lock()获得一个指向共享对象的shared_ptr,然后操作该共享指针。
3、C++中结构体和类区别
1、继承权限:类默认private,结构体默认public;
2、类可以用于定义模板,结构体不可以;
3、访问权限:类默认访问方式是private,结构体是public;
4、重载与重写中const作用
重载中需要参数列表类型、顺序、个数或const不同(const重载需要在类内部,常对象与非常对象调用时发生重载),因此有无const也可作为重载条件。相反的,重写要求参数列表,类型、顺序、个数、返回类型以及有无const均要一致才可重写父类函数,不然仅仅是隐藏了父类同名函数而已(不是虚函数的覆盖虚表)。
5、必须要使用列表初始化情况
1、成员变量有const修饰只读变量或引用。
2、成员类没有默认构造函数,需要手动调用带参构造函数。
3、父类没有默认构造函数,需要手动调用带参构造函数
6、类占用空间
1、空类(C++中结构体也是1字节,c中0字节)占1字节;
2、类也需要按最长数据类型对其;
3、普通函数不占用类空间;
4、static修饰变量不占用类空间;
5、类中如果存在虚函数会多一个虚指针,但是只有一个,一个虚函数和多个对类大小影响都一样;
7、static成员
static成员变量不能在类中初始化,他不属于任何一个对象,属于这个类。同理,static函数也没有this指针。此外,static函数只能访问static变量。
8、引用与指针常量的区别
1、引用是别名,指针常量是实体;
2、引用必须初始化,不能为空;
3、执行++引用是值加,而指针常量是地址加;
4、引用不需要解除引用;
5、sizeof()运算二者不同。
9、构造函数
有4种:默认构造函数、初始化构造函数、拷贝构造函数、移动构造函数。
定义一个类时会生成默认构造函数、拷贝构造函数、赋值运算符、析构函数。
如果只定义了有参数构造函数不会生成默认构造函数。如果定义了拷贝构造函数那就不生成其他构造函数。