当前位置: 首页 > news >正文

html5 网站建设网络科技有限公司电话

html5 网站建设,网络科技有限公司电话,小语种网站建设 cover,简述网站建设的1. static关键字 1.全局static变量 存储位置#xff1a;静态存储区#xff0c;在程序运行期间一直存在 初始化#xff1a; 未手动初始化的变量自动初始化为0 作用域#xff1a; 从定义之处开始#xff0c;到文件结束#xff0c;仅能在本文件中使用 2.局部static变量…1. static关键字 1.全局static变量 存储位置静态存储区在程序运行期间一直存在 初始化 未手动初始化的变量自动初始化为0 作用域 从定义之处开始到文件结束仅能在本文件中使用 2.局部static变量 存储位置静态存储区在程序运行期间一直存在 初始化 未手动初始化的变量自动初始化为0 作用域 为局部作用域 当函数或语句块结束静态变量仍然存在于内存区再次调用函数或进入语句块时可以再次被访问且值保持不变 3.静态函数 静态函数只在声明他的文件内可见无法被其他文件使用若想在其他文件服用复用函数最好把它写在头文件中否则一般加static关键字 4.类的静态成员静态函数 类的静态成员不属于任何一个类可以在对象间共享对于多个对象来说 静态成员存储于一处供所有对象访问对静态函数/静态成员的访问不需要使用对象名。 类的静态函数不能直接引用类的非静态成员可以引用静态成员若要引用非静态成员则需要使用对象名。 总的来说static的作用 一是隐藏当static修饰变量的时候能够将变量或函数对本文件外的文件进行隐藏无法在其他文件中访问。 二是初始化静态存储区分为DATA段和BSS段DATA段存放已经初始化了的全局变量BSS段存放未初始化的全局变量和静态变量在程序执行前BSS段会被清零从而所有静态变量都被初始化为0. 三是延长变量的生命周期若想延长一个变量的生命周期可以把它声明为static比如对于一个函数中的变量在函数下次调用的时候若想仍然使用这个变量 2. 常量指针和指针常量 常量指针表示const修饰的为所申明的类型。 也就是指向常量的指针。也是底层const int const *p1 b; //const 在前定义为常量指针指针常量表示指针是一个常量无法改变其指向的内存空间。 即顶层const int *const p2 c; // 在前定义为指针常量3. C和C的区别 c是C的超集 设计思想不同 C是面向过程的结构化编程语言C是面向对象的语言。 在语法上也存在差别比如c可以使用引用c仅支持指针操作。比如c有三种特性继承封装多态也对c进行了许多类型安全的封装比如强制类型转换这些。而且c支持范式编程支持模板类等等。但是c的高级特性大都是建立在降低效率的基础上实现的c能够以最简便的方式编译处理低级存储器因此更适用于偏底层的设计像嵌入式单片机这些。 4. 浮点数的存储方式 5. 四种强制类型转换 static_cast 可以用于任何有明确定义的类型转换只要不包含底层const 都可以使用static_cast。const_cast 只能改变运算对象的底层const即去掉const性质reinterpret_cast 从运算对象底层的位模式提供低层次上的重新解释不建议使用若使用必须对涉及的类型和编译器的转换过程都十分了解。dynamic_cast 动态类型转换一般用于含有虚函数的类用于类层次间的向下基类向子类的转换或向上转化子类向基类的转换只能转化指针或者引用。 C强制类型转换相对c语言的类型强转相比虽然看起来c语言的强制类型转换功能更强大一些但C封装了更多保证内存安全性的操作因此大多时候最好使用C的强制类型转换。 6. 左值和右值 左值是持久化的变量一般的具名变量都是左值而右值是当前表达式运行结束就销毁的临时对象区分左值右值得简单方法能进行取址符操作的都是左值其他的都是右值。 7. std::move语义 std::move的本质就强制类型转换它无条件地将实参转为右值引用类型std::move 是将对象的状态或者所有权从一个对象转移到另一个对象只是转移没有内存的搬迁或者内存拷贝。 8. C指针和引用的区别 指针 指针是指向另外一种类型的复合类型用于实现数据的间接访问指针本身同样是一个对象它存储指向变量的地址值当需要修改指针指向的变量时需要使用解引用符从而访问修改其指向的地址空间。 引用 相当于给对象起了另外一个名字定义引用时程序把引用和初始值绑定在一起而不是和其他变量一样把初始值拷贝给变量一旦初始化完成则与引用绑定的对象无法进行修改因此定义引用时必须绑定一个初始值。 指针和引用的区别在于 指针拥有属于自己的内存空间是一个实实在在的对象若想操作其指向的对象需要解引用。而引用只是一个别名当对引用使用任何操作符时都是对和它绑定的对象进行操作。指针不必在定义时赋值初始化而引用必须进行初始化绑定。但是指针使用前必须进行赋值否则会产生野指针从而出现问题。指针在它的生命周期内可以指向多个类型符合的对象但引用只能与一个对象绑定。指针可以存在 多级指针但引用只能存在一级因为引用就是该对象的别名。指针和引用自增自减的效果不同指针自增是指其内存中的地址增加一个指向对象类型单位大小的字节而引用自增就只是与其绑定的对象的自增。其实对于大多数编译器而言引用可以被解释为const指针低级语言的特性较少表达的概念有限所以编译器要将高级语言的概念映射到低级语言可能会有很多种解释方式但目前主流编译器都将引用与指针使用相同的方式来描述即分配给引用一个地址空间存储绑定对象的地址当使用引用时就是对它存储的地址解引用后进行操作我们无法访问引用的地址空间。 右值引用 c11增加了一种引用叫右值引用平时我们所指的引用就是左值引用所谓右值引用就是必须绑定到右值的引用使用来定义。 右值引用拥有一个最重要的性质只能绑定到一个将要销毁的对象这样 我们可以将一个右值引用的资源直接移中存在一个std::move函数可以显式的将一个左值变量转换为对应的右值引用类型交给一个右值引用接收。 调用std::move则意味着除了对源对象进行重新赋值或者销毁我们不再使用它即我们不能对移后源对象作任何假设 9. c的三种智能指针 c11标准引入了三种智能指针均定义在头文件下其本质上是一个模板类拥有构造函数和析构函数在超出其作用域后它会主动释放其管理的内存。 shared_ptr shared_ptr是一种共享式指针它引入了一个引用计数的概念对于一块内存每增加一个shared_ptr指向其引用计数1每有一个shared_ptr释放对内存的使用权即销毁指针或指向其他内存则引用计数-1当引用计数为0时则自动释放其之前指向的内存。shared_ptr可以使用方法use_count()查看拥有管理权的shared_ptr的个数可以使用release()方法释放其所有权此时引用计数-1。 unique_ptr 为了保证同一时间仅能有一个指针来管理一块内存c11引入了unique_ptr它是一种独占式指针仅支持一个指针指向该内存。可以使用std::move来移动unique_ptr指向的内存。 weak_ptr 当有两个shared_ptr相互指向发生循环引用时会产生死锁导致内存泄漏因此c11为了防止死锁现象的发生引入了弱引用的概念它的存在不会改变内存的引用计数仅仅用于辅助shared_ptr来管理内存提供一个访问内存的方式可用于核查指针类即检查该对象是否已经被释放。 10. shared_ptr是线程安全的吗 不是线程安全的单独的修改引用计数是原子操作。 11. C多态的原理和实现 C可以使用两种方法实现多态 其一是使用函数重载(overload)也就是编译时多态要求两函数有不同的参数列表 其二是使用虚函数进行函数重写(override)维护一个虚函数表vtbl每个类存在vptr指针指向其vtbl对应的函数。 12. C语言如何实现多态如何实现继承 实现多态使用函数指针手动维护一个虚函数表每个类都使用一个函数指针标记其函数表对应的函数。 继承 将父类作为成员变量封装进子类。 13. 菱形继承的问题 菱形继承就是指 一个派生类有多个基类多个基类又由同一个类派生 这样就会造成一个派生类中同时存在多个基类的基类 编译器无法确定要调用哪个 解决方法 虚继承 C中引入了虚基类其作用是 在间接继承共同基类时只保留一份基类成员 虚继承是声明类时的一种继承方式在继承属性前面添加virtual关键字。 class A//A 基类 { ... };//类B是类A的公用派生类, 类A是类B的虚基类 class B : virtual public A { ... };//类C是类A的公用派生类, 类A是类C的虚基类 class C : virtual public A { ... };14. 什么是虚函数为什么析构函数必须是虚函数为什么C默认构造函数不是虚函数 虚函数是在某个基类中声明在其派生类中被重写的成员函数。用于实现多态性简单来说就是对于不同的类相同的方法可以采用不同的策略。 如果析构函数不是虚函数那么当一个派生类经由一个基类指针删除的时候其结果是未定义的实际实行的时候通常是对象的派生类部分没有被销毁而其中基类部分被销毁掉了就产生了一种局部销毁的现象 从而造成资源泄漏。 为了消除这个问题就必须在基类中定义virtual的析构函数从而销毁对象时才能完整销毁。 如果class是不带虚函数的通常表示它并不意图作为一个基类当class不意图作为一个基类时使用它作为基类往往不是一个好主意。因为想要实现虚函数该对象必须要携带更多的信息用来在运行期决定哪个虚函数被调用这份信息一般由vptr(virtual table pointer)指出vptr指向一个函数指针构成的数组(virtual table)每一个带有虚函数的都存在一个相应的vtbl。当程序运行某个虚函数则实际被调用的函数取决于vptr当前指向的函数。这样为每个类都添加一个虚函数表可能会增加对象大小到50%-100%。因此一般情况下只有当一个class存在至少一个虚函数才认为它可以被当作base class然后为他添加virtual的析构函数。比如stl中的所有模板类就都是不被设计作为base class的 当定义某个对象的时候首先要为它分配空间然后执行构造函数而vptr就是在构造函数中初始化的而又需要查找vptr来决定执行哪个函数这时就陷入了循环。所以不能将构造函数设置为虚函数。 15. 什么是函数指针 函数指针是指向函数的指针变量作为一个可调用对象他能指向所有返回值和参数匹配的函数从而可以传入其他函数分情况调用不同的函数。 int (*fp)(args) typedef int (*fun)(int a,int b);16. 说一下C的三大特性 C的三大特性是封装继承和多态。 封装就是隐藏对象的内部细节只留给使用者几个接口来按设计者的规范来使用该对象。可以隔离开外部使用者对内部数据的干扰提高了安全性同样也便于使用者操作。 继承就是从一个对象继承它的属性和方法可以减少重复代码同时继承也是多态的前提也增加了类的耦合性。 多态就是不同的对象对于相同的方法有不同的操作逻辑一般使用虚函数来实现。它大大提高了代码的可复用性可维护性和可扩充性三大特性是C面向对象的基础正是C与C的最大区别。 17. C如何定义常量常量存放在哪个位置 对于const定义的常变量其本质上就是个只读变量。 对于局部常量在运行前不会为其分配内存会在运行时进行栈上分配。 对于全局常量在运行前就已经存储在了.DATA段中。 18. 如何让一个函数在main函数执行前先执行 写在类的构造函数中定义全局对象在构造时运行。 19. 隐式类型转换 对于内置类型当运算符两端类型不同时编译器会自动使低精度的类型向高精度类型转换。 在类的构造函数中可以直接传入参数编译器会为其生成一个临时对象用于构造。 虽然隐式类型转换很多情况下很方便但是有的时候也会得到我们不想得到的结果所以可以使用explicit关键字禁止编译器进行隐式类型转换。 20. new/delete与malloc/free的区别 new和delete是c的关键字而malloc和free是内置函数当使用new对对象进行分配空间时编译器会自动得到该对象的大小但是malloc需要显式给出需要分配的空间大小。 对于自定义的类来说new会先调用operator new申请足够的空间然后调用类类型的构造函数最后返回该类型的指针delete会先调用类的析构函数然后调用operator delete释放内存空间。而malloc和free是内置函数无法要求他们调用构造函数和析构函数。 21. 什么是RTTI RTTI(Run Time Type Identification)即运行时对类型进行识别即程序在运行中可以根据基类的指针或者引用来识别所指对象的实际派生类它的实际用处主要是在当我们想要使用基类对象的指针或引用来操作它的派生类对象的方法但此方法由于一些原因无法被设置为虚函数。 RTTI机制的功能由两个运算符实现。 一个是typeid运算符返回指针或引用指向的对象的实际类型。但是其操作时作用于对象的所以需要使用取址符当typeid作用于指针的时候将返回该指针的编译时静态类型。 另一个时dynamic_cast 运算符他有三种形式可以传入指针引用与右值引用可以用于类类型的向上或向下转换。 RTTI在有些情况下作用十分明显比如我们需要实现一个有继承关系的类之间的相等运算符我们可以先使用typeid比较两个对象类型是否一致一致则进行每个函数的内置equal函数判断。 22. inline跨文件使用 内联函数必须在调用它的每个文件中定义 若想在所有文件中使用最好在头文件中定义且一旦内联函数在多个头文件中定义则会产生内联函数的重定义 23. 虚函数表具体怎样实现运行时多态 所谓虚函数表是一个类的虚函数地址表在每个对象创建的时候都会有一个vptr指向虚函数表当继承它的子类对虚函数进行重写时虚函数表中的对应函数地址将被新地址覆盖所以当父类指针调用子类的成员函数时虚函数指针就可以指向对应的函数。 当调用虚函数时过程如下引自More Effective C: 通过对象的 vptr 找到类的 vtbl。 这是一个简单的操作,因为编译器知道在对象内 哪里能找到 vptr(毕竟是由编译器放置的它们)。因此这个代价只是一个偏移调整(以得到 vptr)和一个指针的间接寻址(以得到 vtbl)。找到对应 vtbl 内的指向被调用函数的指针。 这也是很简单的, 因为编译器为每个虚函数在 vtbl 内分配了一个唯一的索引。这步的代价只是在 vtbl 数组内的一个偏移。调用第二步找到的的指针所指向的函数。 在单继承的情况下 调用虚函数所需的代价基本上和非虚函数效率一样在大多数计算机上它多执行了很少的一些指令所以有很多人一概而论说虚函数性能不行是不太科学的。在多继承的情况 由于会根据多个父类生成多个vptr在对象里为寻找 vptr 而进行的偏移量计算会变得复杂一些但这些并不是虚函数的性能瓶颈。**虚函数运行时所需的代价主要是虚函数不能是内联函数。**这也是非常好理解的是因为内联函数是指在编译期间用被调用的函数体本身来代替函数调用的指令但是虚函数的“虚”是指“直到运行时才能知道要调用的是哪一个函数。”但虚函数的运行时多态特性就是要在运行时才知道具体调用哪个虚函数所以没法在编译时进行内联函数展开。当然如果通过对象直接调用虚函数它是可以被内联但是大多数虚函数是通过对象的指针或引用被调用的这种调用不能被内联。 因为这种调用是标准的调用方式所以虚函数实际上不能被内联。 24. C语言如何进行函数调用 对于每个函数c都会为它分配一个栈在进行函数调用之前先将当前指令的esp指针压入栈中并将参数入栈跳转到函数存储的地址函数执行结束后恢复esp指针回到原地址继续运行。 25. 拷贝构造函数的调用时机 1.直接初始化和拷贝初始化时 2.将一个对象作为实参传递给一个非引用或非指针类型的形参时 3.从一个返回类型为非引用或非指针的函数返回一个对象时 4.用花括号列表初始化一个数组的元素或者一个聚合类很少使用中的成员时。 26. 当C定义类时编译器会为类自动生成哪些函数这些函数各自都有什么特点 默认构造函数默认析构函数拷贝构造函数默认赋值函数 27. 静态函数和虚函数的区别 静态函数是在编译时就已经确定好了运行的时机而虚函数是使用动态绑定虚函数使用了虚函数表机制调用会增加一次的内存开销。 28. STL由什么组成 容器容纳包含一种元素或元素集合。 迭代器 用于遍历访问容器中的元素一般作为泛型算法的参数。 仿函数 泛型算法用来操作容器中元素的方法。 分配器为容器等分配空间。 配接器将一个class的接口转换为另一个class的接口使原本因接口不兼容不能合作的两个class共同运作。 29. map 和set的区别它们是如何实现的 map和set都是c的关联容器其底层实现都是红黑树他们所有的接口都由红黑树给出所以几乎所有的操作行为都是转调红黑树的操作。 区别 map是映射其中的元素是key-value的可以按key值来索引value值。 set是集合其中元素只是一个值仅包含一个关键字。 set的迭代器是const的它不支持使用迭代器修改元素而map允许修改value的值他们的元素都是根据关键字来保证有序的所以不能轻易修改只能将原关键字删除重新插入但是对于这些操作都是O(logn)的所以时间开销较大。 另外map支持下标操作set不支持。 30. vector 和list的区别它们是如何实现的 vector和list都是c中的容器vector是向量底层存储空间是连续的,也就是数组所以对于随机读取修改所需时间较低为O(1)但插入的复杂度较低每次插入要将其后面的元素向后移动所以最坏时间复杂度是O(n)的。且在可分配空间不足时可能需要将所有的数据移动到另一块内存。 list底层实现是双向链表底层存储时非连续的随机读取只能从头节点向后查找所以最坏时间复杂度是O(n)的但插入仅需 O(1)。 31. 有哪些内存泄漏如何判断内存泄漏如何定位内存泄漏 内存泄漏是指对内存的泄露堆内存在程序中由程序动态分配的内存使用过后需要显示释放有些时候忘记释放已使用完的内存就会发生内存泄漏。若运行过久可能会导致栈溢出致使程序崩溃。 c无法检测内存泄漏但是可以依靠top命令查看进程的动态内存总额也可以使用mtrace来检测定位内存泄漏。 32. 动态链接和静态链接的区别 静态链接 所谓静态链接就是在编译链接时直接将代码拷贝至链接处他的优点是可以独立于库进行发布但是若静态库文件过大容易造成资源的浪费。 动态链接 动态链接就是编译的时候不将代码拷贝到文件而是只复制了一些重定位信息和符号表信息在程序运行或加载时将这些信息传递给操作系统操作系统负责将动态库加载到内存中程序运行到指定代码时再去执行已经加载到内存中的函数。 静态链接存在着明显的缺点一是资源的浪费对于多个可执行文件均调用同一个模块时需要将每个模块都要拷贝到内存中。二是当静态库文件过大时若想更新静态库存在着诸多不便。而动态库就是为了解决这两个问题而生。 动态链接将程序按模块拆分在构建可执行程序时发现该函数十几个外部符号则将其放到运行时进行处理运行时对其进行重定位。动态链接相比静态链接更加灵活解决了模块拷贝到内存时的资源浪费虽然性能相对存在一定的下降但是相比灵活性的提升显然是更值得的。 如何让一个类不能实例化 将类定义为抽象基类或者将构造函数声明为private。 33. C如何创建一个类使得他只能在堆或者栈上创建 只能在堆上生成对象将析构函数设置为私有。 原因C是静态绑定语言编译器管理栈上对象的生命周期编译器在为类对象分配栈空间时会先检查类的析构函数的访问性。若析构函数不可访问则不能在栈上创建对象。只能在栈上生成对象将new 和 delete 重载为私有。 原因在堆上生成对象使用new关键词操作其过程分为两阶段第一阶段使用new在堆上寻找可用内存分配给对象第二阶段调用构造函数生成对象。将new操作设置为私有那么第一阶段就无法完成就不能够再堆上生成对象。 34. C内存管理 c中内存分为五个区域 堆区 程序需要主动申请分配主动释放的区域。可以使用malloc申请栈区 当创建对象时由程序主动分配全局变量区 创建的静态变量或全局变量文字常量区 字面值常量以及字符常量比如printf中的格式化输出字符代码区代码区段 35. 介绍一下allocator new是有局限性的每次new一个对象的时候会将分配空间和构造对象组合在一起有的时候可能会产生一些灵活性上的局限。allocator正是为了解决这个问题而产生的。 一个allocator类调用allocate来分配空间调用construct来构造对象destroy来销毁对象。 36. STL迭代器删除元素 对于顺序容器当使用erase删除元素后会导致排在后面的迭代器失效每个元素向前移动一位但是erase会指向下一个迭代器。 对于关联容器由于底层总是树形结构或者哈希结构对后面的迭代器是没有影响的。 37. 介绍一下模板 模板的目的就是编写与类型无关的代码。 可以使用它来编写函数模板以及类模板。 模板的使用可以增加代码的灵活性和可重用性减少开发时间且模板来模拟多态比类继承实现多态效率会更高一些 但是模板也存在一定问题比如可读性较差调试较困难因为模板的类型只有编译时才能确定所以编译时间会稍长一点。 38. resize和reserve的区别 resize是对改变当前容器元素的数量若resize大小小于当前容器元素的数量则删除后面的元素。 reserve是改变其预留空间保证内存空间可容纳的元素数量并不生成新的对象若参数小于当前容器元素数量则不改变当前的元素数量。 39. C内存对齐 内存对齐就是计算机系统对数据存放位置的限制。 大部分处理器的内存存取粒度是4字节8字节这样的如果不进行内存对齐可能会产生一个整数的存储位置被分到两块内存需要cpu进行两次读取再拼接需要做的工作十分复杂而对齐后可以将一个数据一次直接读取出来提高cpu的读取效率一般编译器默认的内存对齐系数是4在结构体或类中内存对齐系数一般为其成员变量的最大内存对齐系数。 可以使用#pragma pack(n)来改变默认对齐系数 40. 结构体的对齐为什么要对齐 内存对齐主要遵从以下三个原则 结构体变量的起始地址能够被其最宽的成员大小整除结构体每个成员相对于起始地址的偏移能够被其自身大小整除如果不能则在前一个成员后面补充字节结构体总体大小能够被最宽的成员的大小整除如不能则在后面补充字节 为什么需要对齐 1.平台原因(移植原因)不是所有的硬件平台都能访问任意地址上的任意数据的某些硬件平台只能在某些地址处取某些特定类型的数据否则抛出硬件异常。 2.性能原因数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于为了访问未对齐的内存处理器需要作两次内存访问而对齐的内存访问仅需要一次访问。 41. 说一下c的编译过程 编译预处理 预处理阶段主要是做一些代码替换的工作处理预处理指令解包头文件替换宏定义删掉注释等等。 编译、优化阶段 通过词法语法分析将代码文件转换为汇编代码 汇编过程 将汇编代码转换为指定目标的机器指令以便在目标机器上运行。 链接程序 链接程序就是将代码所用到的模块代码片段等连接起来使其可以运行。 42. 深拷贝与浅拷贝 深拷贝是直接将内存拷贝出一份 浅拷贝只是将指针拷贝指向同一块内存 当类成员存在指针时若使用默认构造函数使用简单的浅拷贝那么当使用析构函数释放资源时会提前释放成员指针指向的数据可能造成空悬指针多次释放导致内存泄漏。 43. C 11/14/17新特性 11 智能指针override关键字delete/defaultautofor each语法无序容器nullptrlambda匿名函数右值引用 和 移动语义explicit/override/final/noexceptstd::function 14: 泛型lambda二进制字面值数字分隔符 17 扩展了auto的推断范围嵌套命名空间条件分支语句初始化 44. 零拷贝 所谓的零拷贝Zero-Copy是指将数据直接从磁盘文件复制到网卡设备中而不需要经由应用程序之手 。零拷贝大大提高了应用程序的性能减少了内核和用户模式之间的上下文切换 。 对 Linux操作系统而言零拷贝技术依赖于底层的 sendfile() 方法实现 。 ssize_t sendfile(int out_fd,int in_fd,off_t* offset,size_t count); in_fd参数是待读出内容的文件描述符out_fd参数是待写入内容的文件描述符。offset参数指定从读入文件流的哪个位置开始读如果为空则使用读入文件流默认的起始位置。count参数指定文件描述符in_fd和out_fd之间传输的字节数。 工作原理 系统调用直接通过DMA将数据拷贝到内核缓冲区然后被内核直接转发到与另一个文件相关的内核缓冲区其中一直都是内核态不需要进入用户态。 45. 零拷贝在c中的使用 ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count) ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);45. 什么是线程安全 线程安全是指内存安全也就是保证本线程所使用的数据不被其他线程暗改导致得到的数据不是自己想要的数据。 46. 解决线程安全的办法 使用线程自己的栈内存每个线程都存在自己所独有的栈其他线程无法影响可以把需要保证安全的数据存放在自己的栈区中这样其他线程无法访问也就保证了线程安全对于所需数据copy一份自己的每个线程都copy一份原数据每个线程只访问属于自己的那部分数据也就保证了线程安全定义常变量也就是只读变量保证变量无法被修改。使用互斥锁保证内存中的数据互斥访问。 47. 异常处理 栈展开 在C里当有异常被抛出调用栈(call stack)即栈中用来储存函数调用信息的部分会被按次序搜索直到找到对应类型的处理程序(exception handler)。而这里的搜索顺序就是f1-f2-f3。f1没有对应类型的catch块因此跳到了f2但f2也没有对应类型的catch块因此跳到f3才能处理掉这个异常。 这个寻找异常相应类型处理器的过程就叫做栈展开。 48. 析构函数能否抛出异常 不能。 如果析构函数抛出异常则异常点之后的程序不会执行如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源则这些动作不会执行会造成诸如资源泄漏的问题。通常异常发生时c的异常处理机制在异常的传播过程中会进行栈展开stack-unwinding在栈展开的过程中 会释放局部对象所占用的内存并运行类类型局部对象的析构函数 此时若其他析构函数本身也抛出异常则前一个异常尚未处理又有新的异常会造成程序崩溃。 解决方法 直接结束程序把可能产生异常的代码移出析构函数直接消化处理异常 49. 单例模式 class sigleton { private: sigleton(){};static sigleton* _instance; public:sigleton* instance(){if(!_instance){_instance new sigleton;}return _instance;}}; sigleton* sigleton::_instance 0;多线程安全单例模式 std::mutex mt; class sigleton { private: sigleton(){};static sigleton* _instance; public:sigleton* instance(){if(!_instance){mt.lock();if(!_instance) _instance new sigleton;mt.unlock();}return _instance;}}; sigleton* sigleton::_instance 0;50. std::sort源码剖析 背景 快速排序虽然平均复杂度为O(N logN)却可能由于不当的pivot选择导致其在最坏情况下复杂度恶化为O(N2)。另外由于快速排序一般是用递归实现我们知道递归是一种函数调用它会有一些额外的开销比如返回指针、参数压栈、出栈等在分段很小的情况下过度的递归会带来过大的额外负荷从而拉缓排序的速度。堆排序经常是作为快速排序最有力的竞争者出现平均时间上堆排序的时间常数比快排要大一些因此通常会慢一些但是堆排序最差时间也是O(nlogn)的这点比快排好。 快排在递归进行部分的排序的时候只会访问局部的数据因此缓存能够更大概率的命中而堆排序的建堆过程是整个数组各个位置都访问到的后面则是所有未排序数据各个位置都可能访问到的所以不利于缓存发挥作用。简单的说就是快排的存取模型的**局部性locality**更强堆排序差一些。还有一个问题就是难以并行。 递归调用和循环调用相结合 std::sort 在内部使用使用快速排序 但是为了优化时间复杂度sort将整个序列分为两部分后对于右子区间执行递归调用而对左子区间直接将其分为两部分进行循环调用。这样可以节省一半时间的函数调用节省掉函数调用的时间。 三点中值法 对于快排的基准值sort采用三点中值法取首尾和中间三个值中的中间值作为基准值执行快排。 递归深度阈值 sort设定了一个递归深度阈值初始值是nlogn当达到递归深度阈值时说明该序列存在着恶化倾向函数调用堆排序将该区间进行严格的nlogn复杂度的排序。 最小分段阈值 sort还设定了一个最小分段阈值 一般定义为16 当序列长度达到这个阈值且经过了多次的快速排序的分段序列是存在一定程度的有序的这时调用插入排序可以最优化的处理该子段。 51. lambda表达式底层实现 编译器会把一个lambda表达式生成一个匿名类的匿名对象并在类中重载函数调用运算符。 本质就是因为 lambda 表达式在底层被转换成了仿函数。当我们定义一个lambda表达式后编译器会自动生成一个类在该类中对 () 运算符进行重载实际 lambda 函数体的实现就是这个仿函数 operator() 的实现在调用 lambda 表达式时参数列表和捕获列表的参数最终都传递给了仿函数的 operator()。
http://www.w-s-a.com/news/374751/

相关文章:

  • 如何做com的网站网站建设投标书模板
  • 郑州网络营销网站优化网站技术方案怎么写
  • 济南市住房和城乡建设局网站wordpress mnews主题
  • ios开发网站app网站建设企业有哪些方面
  • 网站主页 优帮云深圳代做网站后台
  • app 与网站网站建设要做什么
  • 厦门国外网站建设公司郑州核酸点推vip服务
  • 免费网线seo外链怎么做
  • 宽带技术网网站wordpress widget hook
  • 山西省住房和城乡建设厅网站报名wordpress添加标签插件
  • 网站怎么自己做外贸网站案例
  • 做网站的优势公司网站怎么做站外链接
  • 海城网站制作建设精准营销的营销方式
  • 北京短视频拍摄公司重庆网站seo推广公司
  • 广州免费推广网站建设4399网页游戏大全
  • 网站的构架与组成建站公司兴田德润
  • php网站部署步骤邯郸哪有做网站的
  • 做设计什么设计比较好的网站南充市住房和城乡建设局考试网站
  • 郑州做系统集成的公司网站龙岩
  • 厦门SEO_厦门网站建设网络营销课程视频
  • vs 2015 网站开发开网店在线咨询
  • 前端如何优化网站性能大学学校类网站设计
  • 中国铁路建设投资公司网站熊学军中国it外包公司排名前50
  • 房产网站的建设广州推广排名
  • 湟源县网站建设wordpress删除未分类
  • 营销型网站开发推广厦门百度seo公司
  • 遵义网站开发培训上海中高风险地区名单最新
  • 禹州市门户网站建设做网站可以申请个体户么
  • 大良营销网站建设效果彩票网站搭建 做网站
  • 做网站的公司为什么人少了在中国如何推广外贸平台