0

関数トレースを使用して独自の例外クラスを構築しようとしています (例外まで呼び出されたすべての関数のファイルと行番号、およびそれらの関数が合計で呼び出された回数を知りたい)

ビルド中は関数トレースが機能しているように見えましたが、適切に使用しようとすると、セグメンテーション違反に悩まされました。私はそれらのいくつかを追跡しました (何かを返すのを忘れたり、アンパサンドを落としたりするようなばかげたエラー)、これは私を殺しています - さらに、私が見ているデバッグステートメントをどのように取得しているのかまだわかりません.

私のコードには多くの改善が必要だと思います(そして、私が絶対にすべきではないことについてのアドバイスや痛烈なコメントに感謝します)が、ここで何が起こっているのかを理解するのを手伝ってくれる人はいますか. FunctionTrace クラスを悪用しようとしましたが、便利だと思うところに cout ステートメントをスローしましたが、どこにも行きません。

取り除かれた int main()、FunctionTrace.{c,h}pp、MathsException.hpp (まだ .cpp はありません)、および gdb からの出力 (まだこれを使用することを学んでいます) を含めます。

main.cpp

#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;
}

FunctionTrace.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();
}

FunctionTrace.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

MathsException.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 しました - まだ役に立たない

おそらく空のオブジェクトを返す前に、いくつかの ifs を追加しました - 同じ seg fault が発生しますが、gdb の出力は異なります (それでも奇妙ですが)

進行状況: 呼び出しの変更

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

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

(および for ループの更新) により、セグ フォールトが削除されました。どういうわけか私のイテレータはどこかばかげたところを指しています

その最後のステップを元に戻しても、セグフォルトは発生しません(以前はそうでした)

4

1 に答える 1

2

のローカル変数への参照を返していますFunctionTraceManager::gatherFunctionCalls

参照はポインターによく似ており、参照を返すと基本的に変数のアドレスが返されます。ただし、関数が戻るときに関数内のローカル変数がスコープ外になるため、それらの変数を (ポインターまたは参照を介して) 参照することはできません。これは未定義の動作であり、動作することもありますが、プログラムがクラッシュするなど、奇妙なことがよく起こります。

于 2012-10-24T01:49:23.150 に答える