程序笔记   发布时间:2022-07-21  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了C++ 学习记录大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_616_0@new 与 malloc的异同处

new 和 delete 是关键词,malloc以及free 需要包含头文件,new 先分配空间再进行构造,delete 先析构后销毁空间。new分配空间失败时会有 bad::alloc 异常, malloc 则会返回NULL。new返回指向对象的指针,而malloc返回 void*指针,需要再进行类型转换

@H_616_0@volatile

告知编译器,变量会随时改变,每次需要该变量时都要去内存里读取。 访问寄存器比访问内存要快得多,因此cpu优先访问寄存器里存储结果,但是内存中的数据可能已经发生了变化,为了避免这种情况使用valatile声明该变量,告诉cpu每次都要去内存中读取该数据。

@H_616_0@define 和const的区别(编译阶段、安全性、内存占用等)

define在预编译期进行简单的替换工作,不进行类型检查,不能调试,可以用来进行防卫式声明,防止头文件重复引用,头文件中尽量只包含声明,不包含定义,可以减弱文件间的编译依存关系,减少编译时期的性能消耗。

const带类型,是常量,编译运行期间起作用,存储在数据段空间。不能重定义

@H_616_0@sizeof(class)

虚函数,成员函数和静态数据成员都不占用对象存储空间,空 class 的大小为1。

@H_616_0@C++内存管理

C++中内存分为五个区,分别是堆,栈,自由存储区,全局/静态存储区和常量存储区。

:执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算符内置于处理器的指令集中,效率较高,但是分配的内存空间有限。

:由malloc分配的内存块,堆是由操作系统所维护的一块特殊内存,它提供了动态分配的功能。使用free释放空间。

自由存储区:由new分配的内存块,它和堆十分相似,不过是由delete来释放空间

全局/静态存储区:全局变量和静态变量的存储是放在一块的(全局变量就是采取静态存储方式的),初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域, 程序结束后由系统释放。

常量存储区:里边存放的常量,不允许修改。

堆和栈区别

区别主要由六点,管理方式不同,空间大小不同,能否产生碎片不同,生长方式不同,分配方式不同以及分配效率不同。

管理方式:对于栈而言,由编译器自动管理,无需我们手工控制,对于堆而言,释放由程序员指定,容易产生@H_813_20@memory leak

空间大小:一般在32位系统下,堆内存可以达到4G的空间,对于栈而言内存空间较小。

碎片问题:对于堆而言,频繁的调用new/delete会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈而言,不会存在该问题,因为栈使先进后出的队列。

生长方向:堆是向着内存地址增加的方向,对于栈而言,向着内存地址减小的方向增长。

分配方式:堆是动态分配的,没有静态分配的堆。栈由两种分配方式,静态和动态分配。栈的静态分配由编译器完成,比如局部变量的分配,动态分配由alloca函数进行分配,栈的动态分配也不跟堆一样,栈动态分配的内存由编译器进行释放。

分配效率:栈是由机器提供的数据结构,计算机会在底层对栈提供支持,效率较高。比堆的效率要高很多。

@H_616_0@面向对象的三大特性

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。在C++中可以使用private以及protected关键词将成员封装起来,只提供一些成员函数对成员进行合理的访问。也就是说封装可以使用户不需要关系实现细节,只需要关系如何去使用它即可。

继承:当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。继承代表is a关系,例如哺乳动物是动物。c++有三种继承方式,分别为private,protected以及public,

多态:多态意味着一个接口,多种方法。多态性指相同对象收到不同消息或不同对象收到相同消息时产生的不同的实现动作。C++支持两种多态,编译时多态以及运行时多态。

​ 编译时多态(函数重载):通过重载函数实现

​ 运行时多态(动态多态):通过虚函数实现(虚函数指针(指向虚函数表)地址位于所有成员变量之前,)

​ 多态的目的:封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了“接口重用”。也即,不论传递过来的究竟是类的哪个对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。

@H_616_0@虚函数

同一个类的不同对象共用一份虚函数表,他们都通过一个所谓的虚函数表指针__vptfr(void **)来指向该虚函数表(vs编译器),在一个子类继承两个父类的条件下,一个父类没有虚函数,另一个父类有虚函数例如

class Base1
{
public:
    int base1_1;
    int base1_2;
};
 
class Base2
{
public:
    int base2_1;
    int base2_2;
 
    virtual void base2_fun1() {}
    virtual void base2_fun2() {}
};
 
// 多继承
class Derive1 : public Base1, public Base2
{
public:
    int derive1_1;
    int derive1_2;
 
    // 自身定义的虚函数
    virtual void derive1_fun1() {}
    virtual void derive1_fun2() {}
};

可以看到base1没有虚函数,但是实际集成时有虚函数的类地址在第一个

谁有虚函数表,谁往前靠。

虚函数存在效率的问题,因为其在执行过程中会进行跳转,动态绑定,与静态绑定的函数相比效率会降低一下,cache命中率也会更低。

@H_616_0@引用可否实现动态绑定

可以。因为引用(或指针)既可以指向基类对象也可以指向派生类对象,这一事实是动态绑定的关键。用引用(或指针)调用的虚函数在运行时确定,被调用的函数是引用(或指针)所指的对象的实际类型所定义的。

@H_616_0@深拷贝和浅拷贝的区别

当有动态生成的对象时,默认拷贝函数是浅拷贝,指向同一块内存区域,析构时两次析构,会有内存泄露。

@H_616_0@遇到coredump要怎么调试

程序崩溃会产生core dump,一般有段错误或者abord。如果有设置core文件的话,就gdb test.cpp core,然后会定位到出错的地方,可以用bt(BACktrance)或者where来查看当前调用的堆栈,然后用frame n找到第n层堆栈的信息,就可以找到出错的语句了;然后进一步分析,p可以查看变量的值。

@H_616_0@C++的四种强制转换

static_cast 可以实现C++种内置类型基本数据类型之间的转换。

const_cast 可以把const属性去掉或者本来不是const的变量加上const属性

reinterpret_cast 它可以转化任何内置的数据类型为其他任何的数据类型,也可以转化任何指针类型为其他的类型。它甚至可以转化内置的数据类型为指针,无须虑类型安全或者常量的情形。不到万不得已绝对不用。

dynamic_cast 其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查.不能用于内置的基本数据类型的强制转换。如果转换成功的话返回指向类的指针或引用,转换失败则返回NULL。使用dynamic_cast进行转换,基类一定要有虚函数,否则编译无法通过。

@H_616_0@智能指针

智能指针使用了一种RAⅡ(资源获取即初始化)技术对普通指针进行封装,这使得智能指针实质是一个对象,行为表现的像一个指针。

unique_ptr: 唯一拥有所指向对象,同一时刻只能有一个unique_ptr指向给定对象(将拷贝函数禁用,只有移动语义std::move函数)。nique_ptr指针与其所指对象的关系:在智能指针生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权。

weak_ptr: 为了配合shared_ptr引入的只能指针,其不具有普通指针的行为(没有重载 operator*以及operator ->,weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()== 0但是更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获取一个shared_ptr对象,但是当 expired() == true时,lock()将返回一个存储空指针的对象。

shared_ptr:shared_ptr多个指针指向相同的对象。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,自动删除所指向的堆内存。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。

  • 初始化。智能指针是个模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。不能将指针直接赋值给一个智能指针,一个是类,一个是指针。例如std::shared_ptr p4 = new int(1);的写法是错误的.

  • 拷贝和赋值。拷贝使得对象的引用计数增加1,赋值使得原对象引用计数减1,当计数为0时,自动释放内存。后来指向的对象引用计数加1,指向后来的对象。

  • get函数获取原始指针

  • 注意不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存

  • 注意避免循环引用,shared_ptr的一个最大的陷阱是循环引用,循环,循环引用会导致堆内存无法正确释放,导致内存泄漏。

大佬总结

以上是大佬教程为你收集整理的C++ 学习记录全部内容,希望文章能够帮你解决C++ 学习记录所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。