打印完整的递归调用栈
之前在写0-1背包问题的递归解法时,想要弄出完整的递归栈。尝试了使用debug工具手工追踪并画出调用栈,发现太麻烦了,又试了一下使用visual studio的code map功能,发现对于递归,它只会显示递归函数不断调用自己,并不会自动展开成为树的形式。所以我就使用了最简陋的办法,就是自己写了一个类,依赖C++的constructor和destructor来自动将栈输入到一个vector中,并且在main函数结束的地方添加一个语句将其内容输出到文件中。
这里使用了一些C++11的特性,我使用mingw和msvc2015编译通过了,其它的编译器就不知道了。
下面是这个类的代码,写的很不完善:
//stacktrace.h
//stacktrace.cpp
以下是结果范例:
这里有别人写的类似的类:A Simple C++ Function Call Stack Trace Utility
来自为知笔记(Wiz)
这里使用了一些C++11的特性,我使用mingw和msvc2015编译通过了,其它的编译器就不知道了。
下面是这个类的代码,写的很不完善:
//stacktrace.h
#ifndef STACKTRACE_H#define STACKTRACE_H#include#include#include/*** 这个类还比较简单粗暴,没有实现字符串格式化参数的软编码(如果需要可以使用boost::format()来像sprintf()一样格式化),* 也没有作为模板类实现以完成可变形参构造函数(注意不要使用C语言的va_arg)。* 使用的时候需要根据需求进行修改。** 使用方法:* 在main函数中setSpaceLength(unsigned length)来控制格式,如果不做这一步,则默认spaceLength = 4* 在需要进行stack trace的函数所在的文件中include "stacktrace.h"* 在需要进行stack trace的函数开头加上一句 StackTrace(capacity, itemNum); capacity和itemNum是需要打印到stack trace的数据* 在main函数的结尾加上一句writeToFile(std::ostream &os, StackTrace::outputType type = reformat);** 如果需要修改这个类的显示效果,只需要修改 StackTrace(double capacity, int itemNum);* 注意:每一行的结束需要写入一个换行符**/class StackTrace{private: //private data fieldstatic int depth;static std::vector<std::string> content;static unsigned spaceLength;static std::vectorfirstNotSpace; public: //public data fieldenum outputType{raw,reformat};public: //constructor and copy controlStackTrace(double capacity, int itemNum);virtual ~StackTrace(){--depth;}public: //public member functionstatic void setSpaceLength(unsigned length);static void writeToFile(std::ostream &os, outputType type = reformat);private: //private member functionstatic void clear();static void outputResult(std::ostream &os);static void generateFirstNotSpace();static void textReplace();};#endif // RECURSIONSTACKTRACE_H
//stacktrace.cpp
#include "stacktrace.h"#include#include#include#include#include#includeusing namespace std;int StackTrace::depth = 0;std::vector<std::string> StackTrace::content;unsigned StackTrace::spaceLength = 4;std::vectorStackTrace::firstNotSpace; void StackTrace::clear(){content.clear();firstNotSpace.clear();}void StackTrace::setSpaceLength(unsigned length){spaceLength = length;}StackTrace::StackTrace(double capacity, int itemNum){++depth;ostringstream temp;int i;for(i = 0;i<depth-1;++i){for(unsigned j= 0;j<spaceLength;++j)temp << " ";//cout << " ";}if(i<depth){if(spaceLength==0); //null statementelse{temp << "└";for(unsigned j=0; j<spaceLength-1; ++j)temp << "-";}}temp << "(" << itemNum << ", " << capacity << ")" << endl;content.push_back(temp.str());}void StackTrace::writeToFile(std::ostream &os, outputType type){if(type == reformat){generateFirstNotSpace();textReplace();}outputResult(os);clear();}void StackTrace::outputResult(ostream &os){for(const string &temp:content)os << temp;os << flush;}void StackTrace::generateFirstNotSpace(){for(size_t i= 0; i<content.size();++i)firstNotSpace.push_back(content[i].find_first_not_of(' '));}void StackTrace::textReplace(){for(size_t i=1; i<content.size();++i){size_t pos = 0;while((pos = content[i].find("└",pos)) != string::npos){for(int j = i-1;j>=0;--j){if(firstNotSpace[j]==string::npos)continue;if(firstNotSpace[j] <= pos )goto END2LOOP;else{content[j][pos] = '|';continue;}}}END2LOOP: ;}}
以下是结果范例:
└---(5, 3)└---(4, 1)| └---(3, 0)| └---(3, 1)| └---(2, 1)| └---(1, 0)| └---(1, 1)| └---(0, 0.9)| | └---(-1, 0.6)| | └---(-1, 0.9)| └---(0, 1)| └---(-1, 0.7)| └---(-1, 1)└---(4, 3)└---(3, 2)| └---(2, 2)| └---(1, 1)| | └---(0, 0.9)| | | └---(-1, 0.6)| | | └---(-1, 0.9)| | └---(0, 1)| | └---(-1, 0.7)| | └---(-1, 1)| └---(1, 2)| └---(0, 1.9)| | └---(-1, 1.6)| | └---(-1, 1.9)| └---(0, 2)| └---(-1, 1.7)| └---(-1, 2)└---(3, 3)└---(2, 3)└---(1, 2)| └---(0, 1.9)| | └---(-1, 1.6)| | └---(-1, 1.9)| └---(0, 2)| └---(-1, 1.7)| └---(-1, 2)└---(1, 3)└---(0, 2.9)| └---(-1, 2.6)| └---(-1, 2.9)└---(0, 3)└---(-1, 2.7)└---(-1, 3)
这里有别人写的类似的类:A Simple C++ Function Call Stack Trace Utility
来自为知笔记(Wiz)