C++踩坑指南
深入学习C++知识
Vincent's Blog
A bug machine made in HUST
展开
-
记一个bug : C2555 overriding virtual function return type differs and is not covariant from
今天同事遇到一个编译错误找我帮忙看一下。原以为编译错误应该好解决,没想到搞了半天才fix,在此记录一下。由于公司代码涉及机密且比较复杂,不方便贴出来,因此我写了一个简化的例子来展示这个编译错误是如何产生的。1.代码假设我们有一个namespace名为zoo, 在zoo中有一个animal基类,一个name类,还有一个dog类继承自animal类。这三个类分别位于三个头文件。代码如下://animal.h#pragma onceclass Name;namespace zoo { cla原创 2020-12-14 18:04:28 · 1833 阅读 · 0 评论 -
Makefile傻瓜教程
Makefile傻瓜教程Makefile是组织代码编译的一种简单办法。make工具和makefile是比较复杂且强大的,本教程甚至还没有触及到make工具的皮毛,但是作为入门指南,它可以帮助你快速又轻松地为中小型项目创建自己的Makefile。1. 一个简单的例子让我们从一个简单例子开始,首先我们需要准备三个文件。这三个文件分别代表主程序,工具函数的实现和声明。//hellomake.c#include<hellomake.h>int main(){ // call a原创 2020-11-03 17:45:38 · 585 阅读 · 0 评论 -
右值引用
右值引用1. 什么是右值引用右值引用是C++11新加的一种引用类型,是一种仅能绑定到右值上的引用。不同于左值引用仅用一个&表示,右值引用用两个&&表示。int x{ 5 };int& lref{ x }; // l-value refrence initialized with l-value x int&& rref{ 5 } // r-value refrence initialized with r-value 5右值引用有两个非常有用的性原创 2020-10-19 15:35:13 · 3746 阅读 · 1 评论 -
智能指针和移动语义
intro to smart pointer and move semantics(翻译改写自https://www.learncpp.com/cpp-tutorial/15-1-intro-to-smart-pointers-move-semantics/)1. 裸指针导致的内存泄漏问题考虑下面这个函数,在这个函数中我们动态申请了一片内存。void someFunction(){ Resource *ptr = new Resource; // Resource is a struct原创 2020-10-19 11:03:34 · 713 阅读 · 0 评论 -
MacOS静态链接和动态链接
上一篇文章已经讲过了window系统下如何制作使用静态链接库和动态链接库, 这篇文章我们来看一下在Mac系统(Linux系统也是一样)下面如何制作静态链接库和动态链接库太长不看版假设我们有一个util.cpp文件和main.cpp文件,在main文件中调用util.cpp文件中定义的函数。我们把util.cpp文件制作成静态库和动态库。生成目标文件g++ -c util.cpp -o util.o打包静态库ar crv libutil.a util.o生成动态库g++ -sh原创 2020-10-17 12:32:23 · 1048 阅读 · 0 评论 -
如何正确删除vector中的元素
今天来探讨C++中的一个基础问题。如何正确地删除`vector`中符合条件的某元素。比如,有一个`vector<int> nums = {1, 2, 2, 2, 2, 3, 5}`,要求删除`nums`中所有值为2的元素。C++初学者可能很快就写出代码:原创 2019-06-18 23:19:37 · 36339 阅读 · 3 评论 -
GDB调试技巧-打印vector的元素值
GDB调试技巧-打印vector的元素值我们平常在使用GDB调试程序的时候,往往需要查看一个STL容器里面存储的元素的值是多少。但是用GDB的p命令打印容器,我们会得到一堆乱七八糟的东。比如有一个vector<int> nums = {1,2,3},当我们使用p nums命令时,我们得到的结果是:(gdb) p nums$1 = {<std::_Vector_base<...原创 2019-05-28 00:16:22 · 10524 阅读 · 3 评论 -
如何实现一个min stack
如何实现一个min stackQ: 如何设计一个特殊的栈,支持min()操作,返回栈中的最小元素.这个问题来源于去年面试遇到的一道题目,面试官给了20分钟时间让设计这样一个栈.当时时间有限,虽然写出来了一个版本,但是那个版本还存在很多的问题,比如不够通用,只能支持int类型数据;同时,效率也不高, 存在大量的数据拷贝.面试完后又仔细思考了一下,重新写了一个版本,记录一下,分享给大家!这个版本...原创 2019-05-08 13:31:43 · 754 阅读 · 0 评论 -
从汇编的角度理解什么是引用
C++中引入的引用类型,给我们带来了很大的方便。通过向函数传递引用,我们既可以享受像传递指针一样直接修改变量值的优点,又避免了空指针和野指针造成的问题。在日常开发中我们应该尽量使用引用,避免使用指针。但是引用到底是什么,看起来好像引用跟指针有着千丝万缕的联系,同时两者又有很大的差别,那么引用跟指针到底是什么关系呢?教材上通常会说,引用就是变量的别名,但是光看这句话可能还是不太明白引用的本质。其实按...原创 2019-03-15 23:42:06 · 1290 阅读 · 0 评论 -
记一个输入缓冲bug
在论坛上看到一个同学贴的一段代码如下:#include<stdio.h>int main(){ int num, cnt, sum = 0; cnt = scanf("%d", &num); while (cnt != 1) { printf("cnt = %d\n", cnt); cnt = scanf("%d",...原创 2019-03-15 23:39:46 · 284 阅读 · 0 评论 -
C++两种构造方法的效率对比
0. 为什么初始化列表效率高?C++中类的构造函数写法有两种,一种是使用初始化列表,一种是在代码块中赋值。很多书中(包括C++ Primer、C++ Primer Plus等等)都会提到应该尽量使用初始化列表而不是在代码块中赋值,因为使用初始化列表通常比在代码块中赋值效率要高。但是这个结论是怎么来的?如何验证呢?今天我们来设计一个小例子对比一下两者之间的区别。1. 定义一个Man类首先,我们...原创 2019-03-10 13:24:52 · 1170 阅读 · 0 评论 -
自己动手实现vector
有了实现string的基础,在加上一点点模板的知识,就可以自己动手实现一个vector了。下面是我实现的代码,比较简单。有点犯懒了,讲解以后再写吧!#ifndef MY_VECTOR_H#define MY_VECTOE_H#include&lt;cassert&gt;typedef unsigned int size_t;template &lt; class T&gt;class...原创 2019-03-09 14:04:02 · 2695 阅读 · 0 评论 -
深入理解static关键字(2)
上一篇文章当中讨论了C语言中static关键字的用法。这一篇来看一下C++中的static。C语言中的用法在C++中一样适用,但是C++中static又新增了一种用法,用来修饰类的成员,称为类的静态成员。1.static修饰类的成员类的静态成员不属于任何对象,类的实例中不包含任何与静态数据成员有关的数据。举个例子:// teacher.hclass teacher {public: ...原创 2019-03-07 20:55:27 · 356 阅读 · 0 评论 -
深入理解static关键字(1)
static关键字是C和C++中很重要的一个关键字,初学者往往搞不清楚这个关键字的真正含义。很多人把这个关键字与变量作用域混为一谈,这种认识是严重错误的!static确实跟变量的作用域有一些关系,但是这两者并不是一回事。这篇文章来探讨一下static关键字的含义,首先放结论:static用于修改标识符(变量或者函数)的链接属性或者存储类型!static用于修改标识符(变量或者函数)的链接属性...原创 2019-03-06 17:28:38 · 673 阅读 · 2 评论 -
如何实现一个string类(2)
上一篇文章实现了myString类的构造函数、拷贝构造函数和析构函数,并且重载了<<运算符。这篇文章来讨论一下赋值运算、下标操作和+=拼接字符串操作。1. 赋值运算符重载首先来看一下赋值运算符重载。在实际应用中,我们经常遇到需要将一个对象赋值给另外一个对象的情况,那么就需要使用赋值运算符=。跟默认的拷贝构造函数一样,如果我们没有显式地定义一个赋值运算符重载函数,那么编译器会提供一...原创 2019-03-04 11:54:04 · 495 阅读 · 0 评论 -
如何实现一个string类(1)
string类是C++当中用的非常频繁的一个类,它提供了很多处理字符串的函数,让字符串的使用变得像int、float等built-in类型一样简单。string类的实现包含了大量c++语言的知识,其中有很多值得讨论的问题。自己动手实现一个string类是学习c++语言的好方法,可以检验自己一下C++基础知识掌握的如何。下面我们来尝试动手实现一个字符串类。1.定义成员变量我们的字符串类需要处理...原创 2019-03-04 11:53:27 · 2416 阅读 · 0 评论 -
如何理解const成员函数
在深入理解const成员函数之前,先来复习一下const关键字的基础用法。1. const修饰某个非指针类型变量const 修饰某个非指针类型变量,表示该变量只读。const int a = 10;a = 20; // 错误,不可以赋值2. const修饰指针const 在*号前面表示指针指向的内容不可更改,指针本身可以改变char buf[] = "hollo, ...原创 2019-02-21 12:01:15 · 1780 阅读 · 0 评论 -
深入理解C++多态
在之前发的一篇文章《虚函数表分析-C++多态的实现》中,已经分析过C++多态的实现原理。这篇文章来看一个具体的例子,这个例子来源于一道经典的C++面试题,看起来蛮简单,但是相当多的人都在这里翻车了。这篇文章希望能把这道题阐述清楚,给大家带来一些帮助。题目给了下面这样一段代码(代码我略有更改),问程序的输出是什么,并解释输出结果。class A {public: int a; v...原创 2019-02-20 13:56:01 · 474 阅读 · 0 评论 -
c++智能指针
0.使用普通指针带来的问题c++ 的内存管理是一个让人非常头疼的问题,当我们写一个new语句时,如果没有写响应的delete语句,就会造成内存泄漏的问题。或者就算我们写了delete语句,有可能程序还没有执行到delete语句就返回或者跳转到其他的语句,一样会造成内存泄漏。看下面这个例子void test(){ double *p = new double; *p = 5.5; ret...原创 2019-01-03 18:08:02 · 360 阅读 · 0 评论 -
构造函数、析构函数和虚函数的关系
首先明确两点构造函数不可能定义为虚函数虚函数的目的是通过父类引用或者指针调用子类的成员函数。而构造函数的目的是创建对象。创建子类对象时,将调用子类的构造函数,而不是父类的构造函数。子类的构造函数将使用父类的一个构造函数。这种顺序不同于继承机制。因此,子类不继承父类的构造函数,所以将类的构造函数声明为虚函数没有意义。这个如果不能理解,记住就好了。父类的析构函数应该是虚函数关于第二点,举个...原创 2019-01-01 22:42:30 · 1863 阅读 · 0 评论 -
虚函数表分析
0.多态C++几个的抽象、封装、继承和多态几大特性当中,多态是最为重要的一个。所谓多态(这里指狭义的多态)就是父类指针或引用指向子类对象,然后可以通过父类指针或引用调用子类的成员函数。 刚开始学习多态的时候,觉得多态非常神奇,同时也非常费解。后来了解到c++的多态是通过虚函数表来实现的,但是一直也没有做一个系统的总结。今天写几个例子梳理一下c++是怎么通过虚函数表来实现多态的。1. 单继承虚函...原创 2019-01-01 14:49:52 · 513 阅读 · 0 评论 -
赋值运算符重载
0.对象赋值时发生了什么C语言中允许把一个结构体赋值给另外一个相同类型的结构体,C++允许把一个对象赋值给另一个同类的对象。这是通过自动为类重载赋值运算符实现的。这种赋值运算符重载函数yuan原型如下。Class_name &amp; Class_name::operator=(const Class_name &amp;);它接受一个指向对象的常引用,并返回一个指向类对象的引用。那么c+...原创 2019-01-01 02:03:33 · 563 阅读 · 0 评论 -
拷贝构造函数总结
0. 什么是拷贝构造函数拷贝构造函数用于将一个对象复制到一个新创建的对象中。也就是说,它用在初始化过程中,而不是常规的赋值操作中。类的拷贝构造函数的原型如下:Class_name(const Class_name&amp;);这个函数接受一个指向类对象的常量引用作为参数。如果没有定义,c++会提供一个默认的拷贝构造函数,不过这个默认的拷贝构造函数有一些坑需要注意(见后面的例子)。编译器新建...原创 2019-01-01 01:15:51 · 655 阅读 · 0 评论