0

我正在尝试使用函数跟踪构建自己的异常类(我想知道调用异常的所有函数的文件和行号,以及它们函数被调用的总次数)

功能跟踪似乎在构建它时起作用,但是当尝试正确使用它时,我被分段错误所困扰。我已经追踪了其中的一些(愚蠢的错误,比如忘记返回任何东西或丢弃 & 号),但是这个让我很生气——而且我还无法弄清楚我是如何得到我看到的调试语句的。

我希望我的代码需要大量改进(对于任何关于我绝对不应该做的事情的建议或严厉评论,我将不胜感激),但谁能帮我弄清楚这里发生了什么。我试图利用我的 FunctionTrace 类,并在我认为有用的地方抛出 cout 语句,但我无处可去。

我包括一个剥离的 int main()、FunctionTrace.{c,h}pp、MathsException.hpp(还没有 .cpp)和 gdb 的输出(仍在学习使用它)

主文件

#include <iostream>
#include "FunctionTrace.hpp"
#include "MathsException.hpp"

using namespace std;

int main(int argc, char* argv[])
{
    LOG_FUNC_CALL
    try
    {
        std::string test = "";
        MathsException oExc(test);
        throw oExc;
    }
    catch(MathsException& iException)
    {
        iException.what();
    }
    return 0;
}

函数跟踪.cpp

#include "FunctionTrace.hpp"
#include <vector>
#include <string>
#include <iostream>
#include <stdio.h>

static int countDebugStatic = 0; //TODO delete me!

int& FunctionCallDetails::getLine(){return lineNumber;}

const char* FunctionCallDetails::getFile(){return file;}

int& FunctionCallDetails::getNoOfTimesCalled(){return noOfTimesCalled;}

FunctionTrace::FunctionTrace(const int iLineNumber, const char* iFile)
{
    FunctionTraceManager& fnTraceMgr = FunctionTraceManager::getInstance();

    int oTimesCalled = ++fnTraceMgr.getAllTimesCalled()[std::make_pair(iLineNumber, iFile)];
    fnTraceMgr.getAllFunctionCalls().push_back(FunctionCallDetails(iLineNumber, iFile, oTimesCalled));
}

std::vector<std::string>& FunctionTraceManager::gatherFunctionCalls()
{
    FunctionTraceManager& fnTraceMgr = FunctionTraceManager::getInstance();
    std::vector<FunctionCallDetails>::iterator fnCallsIter =  fnTraceMgr.getAllFunctionCalls().begin();
    std::vector<std::string> oFnDetails;
    for(; fnCallsIter != fnTraceMgr.getAllFunctionCalls().end(); ++fnCallsIter)
    {
        countDebugStatic++;
        std::cout << "count: " << countDebugStatic << "\n";
        std::string fnDetail = "Function at line: ";
        char lineCalled[11]; //I'd never live long enough to generate this many lines of code in one file
        snprintf(lineCalled, 10, "%d", fnCallsIter->getLine());
        fnDetail += lineCalled;
        fnDetail += ", in file: ";
        fnDetail += fnCallsIter->getFile();
        fnDetail += " called: ";
        char noOfTimesCalled[11]; //log(2^32)/log(10) = 9.~~ (need a null char) 
        snprintf(noOfTimesCalled, 10, "%d", fnCallsIter->getNoOfTimesCalled());
        fnDetail += noOfTimesCalled;
        fnDetail += " times.";
        oFnDetails.push_back(fnDetail);
        std::cout << "fnDetail: " << fnDetail << "\n";
    }
    if(oFnDetails.size() > 0)
    {
        return oFnDetails;
    }
    else
    {
        oFnDetails.push_back("");
        return oFnDetails;
    }
}


FunctionTrace::~FunctionTrace()
{
    FunctionTraceManager& fnTraceMgr = FunctionTraceManager::getInstance();
    fnTraceMgr.getAllFunctionCalls().pop_back();
}

函数跟踪.hpp

#ifndef FUNCTION_TRACE_HPP
#define FUNCTION_TRACE_HPP

#include <vector>
#include <string>
#include <map>
#include <iostream>

class FunctionCallDetails
{
    int lineNumber;
    const char* file;
    int noOfTimesCalled;
    public:
        FunctionCallDetails(const int iLineNumber, const char* iFile, int iTimesCalled): lineNumber(iLineNumber), file(iFile), noOfTimesCalled(iTimesCalled){};
        int& getLine();
        const char* getFile();
        int& getNoOfTimesCalled();
};

class FunctionTraceManager
{
    //singleton
    std::vector<FunctionCallDetails> functionCalls;
    std::map<std::pair<const int,const char*>,int> timesCalled;

    FunctionTraceManager(){}
    FunctionTraceManager(FunctionTraceManager const&){}
    ~FunctionTraceManager(){}
    void operator = (FunctionTraceManager const&){}

    public:
        //this method will be the only way to get a FnTraceMgr object, and once statically created, further calls will retrieve the first (and only) FnTraceMgr
        //Object created.
        static FunctionTraceManager& getInstance()
        {
            static FunctionTraceManager fnTraceMgrInstance;
            return fnTraceMgrInstance;
        }
        std::vector<FunctionCallDetails>& getAllFunctionCalls()
        std::map<std::pair<const int,const char*>,int>& getAllTimesCalled()
        {
            if(functionCalls.size() > 0)
            {
                return functionCalls;
            }
            else
            {
                functionCalls.push_back(FunctionCallDetails(-1,"",-1));
                return functionCalls;
            }
        }
        std::map<std::pair<const int,const char*>,int>& getAllTimesCalled(){return timesCalled;}
        std::vector<std::string>& gatherFunctionCalls();
};
class FunctionTrace
{
    public:
        FunctionTrace(const int iLineNumber, const char* iFile);
        ~FunctionTrace();
};

#define LOG_FUNC_CALL FunctionTrace functionTrace(__LINE__,__FILE__);
#endif

数学异常.hpp

#ifndef MATHS_EXCEPTION_HPP
#define MATHS_EXCEPTION_HPP
#include <exception>
#include "FunctionTrace.hpp"



#include <iostream>
class MathsException : public std::exception
{
    std::string errMsg;
    public:
        MathsException() throw() { LOG_FUNC_CALL };
        MathsException(const std::string iMsg): errMsg(iMsg){ LOG_FUNC_CALL }
        MathsException(const char* iMsg): errMsg(iMsg){ LOG_FUNC_CALL }
        std::string appendFunctionTracing()
        {
            LOG_FUNC_CALL
            std::string oStr = "";
            FunctionTraceManager& fnTraceMgr = FunctionTraceManager::getInstance();

            std::cout << "Why am I not seeing this at all !???";
            std::cout << "Why am I only seeing this once !???  fnTraceMgr.gatherFunctionCalls().size(): " << fnTraceMgr.gatherFunctionCalls().size() << "\n";
            std::vector<std::string>::iterator fnCallsIter = fnTraceMgr.gatherFunctionCalls().begin();
            for(; fnCallsIter != fnTraceMgr.gatherFunctionCalls().end(); ++fnCallsIter)
            {
                oStr += *fnCallsIter;
                oStr += "\n";
            }
            oStr += errMsg;
            return oStr;
        }
        void what()
        {
            LOG_FUNC_CALL
            std::cout << appendFunctionTracing();
        }

        ~MathsException() throw(){LOG_FUNC_CALL}
};

#endif

gdb 输出

greg@greg-Aspire-5742:~/Documents/MMath/c++projects/2012_revision/Solver$ gdb Solver
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/greg/Documents/MMath/c++projects/2012_revision/Solver/Solver...done.
(gdb) r
Starting program: /home/greg/Documents/MMath/c++projects/2012_revision/Solver/Solver 
Why am I not seeing this at all !???count: 1
fnDetail: Function at line: -1, in file:  called: -1 times.
count: 2
fnDetail: Function at line: 10, in file: main.cpp called: 1 times.
count: 3
fnDetail: Function at line: 35, in file: MathsException.hpp called: 1 times.
count: 4
fnDetail: Function at line: 18, in file: MathsException.hpp called: 1 times.
Why am I only seeing this once !???  fnTraceMgr.gatherFunctionCalls().size(): 4
count: 5
fnDetail: Function at line: -1, in file:  called: -1 times.
count: 6
fnDetail: Function at line: 10, in file: main.cpp called: 1 times.
count: 7
fnDetail: Function at line: 35, in file: MathsException.hpp called: 1 times.
count: 8
fnDetail: Function at line: 18, in file: MathsException.hpp called: 1 times.
count: 9
fnDetail: Function at line: -1, in file:  called: -1 times.
count: 10
fnDetail: Function at line: 10, in file: main.cpp called: 1 times.
count: 11
fnDetail: Function at line: 35, in file: MathsException.hpp called: 1 times.
count: 12
fnDetail: Function at line: 18, in file: MathsException.hpp called: 1 times.

Program received signal SIGSEGV, Segmentation fault.
0xb7f6e478 in std::string::append(std::string const&) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
(gdb) info locals
No symbol table info available.
(gdb) bt
#0  0xb7f6e478 in std::string::append(std::string const&) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#1  0x0804b564 in operator+= (__str=..., this=0xbffff138) at /usr/include/c++/4.6/bits/basic_string.h:925
#2  MathsException::appendFunctionTracing (this=0x80530d8) at MathsException.hpp:27
#3  0x0804989b in what (this=0x80530d8) at MathsException.hpp:36
#4  main (argc=Cannot access memory at address 0x1
) at main.cpp:19
(gdb) info locals
No symbol table info available.
(gdb) up
#1  0x0804b564 in operator+= (__str=..., this=0xbffff138) at /usr/include/c++/4.6/bits/basic_string.h:925
925       { return this->append(__str); }
(gdb) info locals
No locals.
(gdb) up
#2  MathsException::appendFunctionTracing (this=0x80530d8) at MathsException.hpp:27
27              oStr += *fnCallsIter;
(gdb) info locals
functionTrace = {<No data fields>}
oStr = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x80523ac ""}}
fnCallsIter = {_M_current = 0x8053310}
(gdb) up
#3  0x0804989b in what (this=0x80530d8) at MathsException.hpp:36
36          std::cout << appendFunctionTracing();
(gdb) info locals
functionTrace = {<No data fields>}
(gdb) up
#4  main (argc=Cannot access memory at address 0x1
) at main.cpp:19
19      iException.what();
(gdb) info locals
iException = @0x80530d8
functionTrace = {<No data fields>}
(gdb) up
Initial frame selected; you cannot go up.

编辑:在我错过的 FunctionTrace.hpp 的最后几行中添加

Const'd 我能看到的所有参数,看看编译器是否会帮助我 - 仍然没有用

在我返回可能为空的对象之前添加了一些 ifs - 我仍然遇到相同的段错误,但 gdb 输出不同(尽管仍然很奇怪)

进展: 改变电话喜欢

std::vector<FunctionCallDetails>::iterator fnCallsIter =  fnTraceMgr.getAllFunctionCalls().begin();

std::vector<FunctionCallDetails> fnCalls =  fnTraceMgr.getAllFunctionCalls();
std::vector<FunctionCallDetails>::iterator fnCallsIter =  fnCalls.begin();

(并更新 for 循环)已消除 seg 错误;不知何故,我的迭代器一直指向某个愚蠢的地方

并撤消最后一步我没有遇到段错误(以前我做过)

4

1 回答 1

2

您正在返回对FunctionTraceManager::gatherFunctionCalls.

引用很像指针,返回引用基本上返回变量的地址。但是,由于函数返回时函数中的局部变量超出范围,因此无法引用这些变量(通过指针或引用)。这是未定义的行为,有时可能会起作用,但经常会发生奇怪的事情,例如程序崩溃。

于 2012-10-24T01:49:23.150 回答