之前开发用Linux C比较多,C++中的STL 容器基本没有接触过。最近在学习C++,平时用到c++ 17中的部分新特性,下面就简单分享下自己C++的学习流程。
一、环境搭建
     本人使用的是CentOS 7系统,该系统默认的g++版本不支持c++17的新特性。所以,首先需要做的就是升级新版本的g++。
  1. ftp://ftp.mirrorservice.org/sites/sourceware.org/pub/gcc/releases/网站上选择支持c++17的gcc版本,并使用wget下载到Linux系统中:wget ftp://ftp.mirrorservice.org/sites/sourceware.org/pub/gcc/releases/gcc-7.1.0/gcc-7.1.0.tar.bz2
  2. 安装编译gcc需要的依赖包 sudo yum install gmp-devel mpfr-devel libmpc-devel -y
  3. 解压gcc压缩包到temp文件夹  tar -jxf gcc-7.1.0.tar.bz2 -C temp
  4. 进入到temp/gcc目录下,执行 gcc ./configure --enable-checking=release --enable-languages=c,c++ --disable-multilib && make 进行gcc的编译(这个步骤耗时较长)
  5. 安装新版gcc  sudo make install
  6. 由于在./configure阶段未指定安装路径,那么新版的gcc的默认安装位置就是/usr/local/目录下,修改标准库的软连接使其指向新版本的标准库 sudo ln -sf /usr/local/lib64/libstdc++.so.6.0.23 /lib64/libstdc++.so.6
  7. 需要使用c++17的特性时,需要在Makefile的CXXFLAGS变量中添加 -std=c++17 
 
     gdb默认情况下是不支持c++容器输出的,不过在gdb 7.0版本之后,可以通过添加插件的方式来支持c++容器输出
  1. 检查gdb版本 gdb --version, (如果版本号低于7.0就不用往下看了)
  2. 在当前用户的home目录中(如/home/sxhlinux)下载 插件代码 svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python (没有svn的,需要通过 sudo yum install svn -y 安装)然后执行mv python .gdb_stl 将该文件夹重命名(使其隐藏)
  3. 执行 vim ~/.gdbinit,编辑gdb配置文件,添加如下内容
    add-auto-load-safe-path /usr/local/lib64/libstdc++.so.6.0.23-gdb.py  #文件的版本号,根据这个目录中的实际文件版本号确定
    
    python
    import sys
    sys.path.append("/usr/local/share/gcc-7.1.0/python")
    sys.path.insert(0, '/home/sxhlinux/.gdb_stl') #注:将第二个参数中的路径改成自己的.gdb_stl文件夹路径
    from libstdcxx.v6.printers import register_libstdcxx_printers
    register_libstdcxx_printers (None)
    end
 
二、gdb 调试示例
  1. 下面的代码是将带有数字特征的分词(用unorder_map保存),按照一定的规则(分词的数字特征)进行合并

    #include <iostream>
    #include <cstdlib>
    #include <map>
    #include <unordered_map> using namespace std; template <typename T1, typename T2>
    bool merge_tokens(T1 &target, const T2 &rules)
    {
    auto pre = target.begin();
    for (auto token = target.begin(); token != target.end(); ) {
    if (pre == token) {
    token ++;
    continue;
    } auto range = rules.equal_range(pre->second);
    auto it = range.first;
    for (; it != range.second; it++) {
    if (it->second == token->second) {
    break;
    }
    } if (it == range.second) {
    pre = token;
    token ++;
    }
    else {
    pre->first += token->first;
    // target.insert(std::make_pair<typename T1::key_type, typename T1::mapped_type>(pre->first + token->first, 16));
    pre->second = 16;
    token = target.erase(token);
    pre = token;
    }
    }
    } int main ( int argc, char *argv[] )
    {
    unordered_map<string, size_t> tokens = {{"def", 22}, {"ghi", 100}, {"abc", 22}};
    unordered_multimap<size_t, size_t> rules = {{22, 100}, {100, 22}, {1, 38}};
    merge_tokens(tokens, rules); return EXIT_SUCCESS;
    } /* ---------- end of function main ---------- */
 
  1. 编译该文件,提示 31行

    test.cpp:31:15: error: passing ‘const std::__cxx11::basic_string<char>’ as ‘this’ argument discards qualifiers [-fpermissive]
    pre->first += token->first;
    ~~~~~~~~~~~^~~~~~~~~~~~~~ /usr/local/include/c++/7.1.0/bits/basic_string.h:1122:7: note: in call to ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator+=(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
    operator+=(const basic_string& __str)
    ^~~~~~~~
     根据错误提示:string 的运算符 += 要求参数是一个 const string类型(作为右值,非const类型也可以作为const类型的参数使用),返回值是一个string类型。再看 出错的语句 pre->first += token->first; 根据mian函数中的tokens的定义,token和pre的first成员都应该是string而不是const string。
 
  1. 将报错的这一行注释掉,然后用gdb查看下pre->first和token->first的具体类型。具体如下

    (gdb) whatis target
    type = std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long> &
    (gdb) whatis target.begin()
    type = std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long> > >::iterator
    (gdb) whatis pre
    type = std::__detail::_Node_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long>, false, true>
     根据上面显示的,target两个参数类型确实和定义的一样,string和unsigned long;target.begin()类型说明中的std::allocator的模板参数pair的第一个参数为 string const,说明在创建unordered_map时,key的类型为const string而不是string(猜测这跟map与key相关的只有增加、删除而没有修改操作有关)。因为allocator在申请空间时,已经隐式的将string转成了const string,所以,pre->first的类型是const string而不是string(也就无法进行+=,=等相关操作)。
 
  1. 根据第三步的分析结果,要实现合并元素的效果,只能是将合并后的值作为一个新的pair插入到原来的map中,然后将原来的两个pair删除。代码如下:

                target.insert(std::make_pair<typename T1::key_type, typename T1::mapped_type>(pre->first + token->first, 16));
    target.erase(pre);
    token = target.erase(token);
    pre = token;
 
三、总结
     很多时候我们遇到问题首先想到的是将错误复制下来,然后粘贴到google搜索框中,漫无目的的去寻找答案,而不是仔细分析查看gcc给出的错误提示。跟我的经验,很多时候gcc给出的提示相当明显,认真仔细阅读大部分可以很快找出解决方案,剩余的一部分棘手问题可以借助搜索引擎(PS:当搜索英文提示时,如果没有google,可以使用英文版的必应,效果也不错)

一次C++调试记录的更多相关文章

  1. SPI 核软件调试记录

    SPI 核软件调试记录 1.首先说说int SpiFlashWaitForFlashReady(void)这一函数,基本上其它函数在执行的时候,都会事先执行一次此函数.    因为此函数的作用主要是用 ...

  2. Video Timing Controller v6.1软件调试记录

    Video Timing Controller v6.1软件调试记录 GUI配置: . case XVTC_VMODE_PAL: //576i@50 { TimingPtr->Interlace ...

  3. Video Test Pattern Generator(7.0)软件调试记录

    Video Test Pattern Generator(7.0)软件调试记录 . XVidC_VideoMode XVIDC_VM_576_50_I = XVIDC_VM_720x576_50_I ...

  4. MA82G5D16AS16 主频调试记录

    MA82G5D16AS16 主频调试记录 当 SCKS 设置 为 MCKDO / 128 时 MCU 的电流为 0.58mA,100UF 电容可以维持 0.5S,大概可以满足. 但是需要注意外围的线路 ...

  5. Apusic中间件结合MyEclipse进行远程调试记录

    Apusic中间件结合MyEclipse进行远程调试记录. 在金蝶域中正常部署应用. 启动金蝶中间件时使用"startapusic -ds"命令. 在MyEclipse的Run-- ...

  6. http://stblog.baidu-tech.com/?p=1684) coredump调试记录 - PHP篇 原创: 扶墙 贝壳产品技术 今天

    http://stblog.baidu-tech.com/?p=1684) coredump调试记录 - PHP篇 原创: 扶墙 贝壳产品技术 今天

  7. 基于freescale i.Mx6(ARM)的阿里云oss调试记录

    交叉编译阿里OSS调试记录 1.1 开通oss服务 具体参考以下链接: https://help.aliyun.com/document_detail/31884.html?spm=a2c4g.111 ...

  8. [ZJCTF 2019]EasyHeap | house of spirit 调试记录

    BUUCTF 上的题目,由于部分环境没有复现,解法是非期望的 house of spirit 第一次接触伪造堆的利用方式,exp 用的是 Pwnki 师傅的,本文为调试记录及心得体会. 逆向分析的过程 ...

  9. [未完] Linux 4.4 USB —— spiflash模拟usb大容量存储设备 调试记录 Gadget Mass Stroage

    linux 4.4 USB Gadget Mass Stroage 硬件平台: licheepi nano衍生 调试记录 驱动信息 │ This driver is a replacement for ...

  10. 【原】xcode5&IOS7及以下版本免证书真机调试记录

    搞了有一段IOS开发了,之前一直在企业做,近阶段主要在公司做C++服务端开发,打算在空闲实现搞搞个人开发,为自己赚钱,IDP还没申请下来,所以先用此方法在越狱设备上先做一下app的免证书真机调试,先记 ...

随机推荐

  1. iOS Regex匹配关键字并修改颜色

    引入第三方框架RegexKitLite /** * 根据传入的文字返回一个符合规则的富文本 * * @param title 匹配的文字 * * @return 创建的富文本 */ -(NSAttri ...

  2. 《JAVA与模式》之简单工厂模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述简单工厂模式的:简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式.简单工厂模式是由一个工厂 ...

  3. Zepto源码分析-event模块

    源码注释 // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zepto.js may be freely distributed under the MIT l ...

  4. android Activity Application Context 的区别

    用了这么久的Context,对于Context究竟是个什么玩意一直不是很明白.看了网上十几篇文章的介绍 加上自己的理解总结一下.(自己想法,不对勿喷,不想照搬网上一些文字说法来糊弄自己,自己理解的就这 ...

  5. [52PJ] Java面向对象笔记(转自52 1510988116)

    面向对象概念 面向对象三大特征:封装,继承,多态 面向对象编程(OOP,Object Oriented Programing)是相对于面向过程编程说的,之前写的代码基本都是纯的面向过程编程的,当项目复 ...

  6. GPU编程--Shared Memory(4)

    GPU的内存按照所属对象大致分为三类:线程独有的.block共享的.全局共享的.细分的话,包含global, local, shared, constant, and texture memoey, ...

  7. A comparison of local caches (2) 【本地缓存之比较 (2)】

    接上一篇: A comparison of local caches (1) [本地缓存之比较 (1)] This article will compare the asynchronous loca ...

  8. redis五种数据类型

    string Redis的字符串和其他编程语言或者其他键值存储提供的字符串非常相似. 命令 行为 GET 获取存储在给定键中的值 SET 设置存储在给定键中的值 DEL 删除存储在给定中的值(这个命令 ...

  9. Unexpected end of input 和 Unexpected token var 和 Unexpected token ;

    在写jsp的时候使用的一段代码一直调试,出现Unexpected token ; 错误. 所以最后把代码各种精简,得到了如下的测试示例代码 <% String aaa="123&quo ...

  10. cocoapod升级

    1.0 重新安装问题 cd /user/xx/.cocoapod/repos rm -rf master pod setup /user/xx/.cocoapod/repos 查看目录文件夹大小: d ...