C++调试记录与心得分享

 更新时间:2020年4月25日 17:30  点击:1294

 之前开发用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  #文件的版本号,根据这个目录中的实际文件版本号确定

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 ---------- */ 

2. 编译该文件,提示 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。

 3.将报错的这一行注释掉,然后用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(也就无法进行+=,=等相关操作)。

 
4.根据第三步的分析结果,要实现合并元素的效果,只能是将合并后的值作为一个新的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,可以使用英文版的必应,效果也不错)

[!--infotagslink--]

相关文章

  • C++ STL标准库std::vector的使用详解

    vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
  • C++中取余运算的实现

    这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ string常用截取字符串方法

    这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • C++中四种加密算法之AES源代码

    本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
  • 在ASP.NET 2.0中操作数据之七十二:调试存储过程

    在开发过程中,使用Visual Studio的断点调试功能可以很方便帮我们调试发现程序存在的错误,同样Visual Studio也支持对SQL Server里面的存储过程进行调试,下面就让我们看看具体的调试方法。...2021-09-22
  • C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • C++万能库头文件在vs中的安装步骤(图文)

    这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ bitset用法

    这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • Node调试工具JSHint的安装及配置教程

    现在我们介绍一种在Node下检查简单错误的JS代码验证工具JSHint。  JSHint的具体介绍参考http://www.jshint.com/about/,说直白点儿,JSHint就是一个检查JS代码规范与否的工具,它可以用来检查任何(包括server端和client端...2014-05-31
  • 浅谈C++中的string 类型占几个字节

    本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
  • C++ Eigen库计算矩阵特征值及特征向量

    这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • idea 无法debug调试的解决方案

    这篇文章主要介绍了idea 无法debug调试的解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-09
  • C++ pair的用法实例详解

    这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • C++中的循环引用

    虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
  • C++随机点名生成器实例代码(老师们的福音!)

    这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • JavaScrip调试技巧之断点调试

    首先,在各个浏览器中,断点调试支持的最好的当然是Firefox,Firefox不仅可以使用Firebug调试页面js脚本,还可以用高级调试工具例如JavaScript Debugger (Venkman) 来调试Firefox扩展里的js。除此之外,Firefox还支持一些更为...2015-10-23
  • C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25