views:

1091

answers:

5

Hello,

What do gdb users here think about its capabilities in regards to debugging code with templates and STL?

Do you use any tricks to make the debugging any simpler? Perhaps some Python scripts? Or are you satisfied the way it is at present in gdb (ver 6.x, haven't tried 7.x yet)?

Thanks.

+5  A: 

This may be of help: GDB STL Support Tools

Amro
i use these. very useful.
sean riley
+2  A: 

I am assuming that you mean visualizing STL code better (and not the debug mode which give safe iterators and additional runtime checks). I am not sure if you have looked at these posts:

Using gdb

Starting with version 7.0, GDB includes support for writing pretty-printers in Python. Pretty printers for STL classes are distributed with GCC from version 4.5.0. The most recent version of these printers are always found in libstdc++ svn repository. To enable these printers, check-out the latest printers to a local directory:

Also, try using KDevelop/DDD if possible -- they do help.

dirkgently
+1  A: 

My favorite way to use GDB is GDB mode in emacs. You get full visual/source level debugging, thread window, stack window (etc)... Try it out, you won't be disappointed.

That said, GDB handles debugging of STL containers just fine with no special add ons... Just make sure you're building WITH -g, and without -ON (of any kind)...

dicroce
A: 

ddd is great too -- my favorite!

vehomzzz
+1  A: 

I am not sure if you are allowed to add code, or you are just debugging the code, Sorry. I wrote a simple utility functions since a while, I hope you find it useful. You could print the contents of standard containers easily. There is no platform specific code, an example of usage(the test-driver actually):

#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>

#include <vector>
#include <list>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <map>

#include <boost/array.hpp>
#include <boost/assign.hpp>
#include "streamer.hpp"


const std::size_t consoleWidth = 80;

std::ostream& newline_if_not_console(std::ostream& outputstream)
{
    if(&outputstream != & std::cout)
    {
     outputstream << std::endl;
    }

    return outputstream;
}

void STL_test_ostream(std::ostream& out)
{
    using namespace boost::assign;
    using namespace streamer;

    double iDoubleArray[] = {0.1, 1.2, 2.3, 3.4, 4.5}; // It could be of any type!
    std::vector<int>    iVec;
    std::list<int>     iList;
    std::deque<int>     iDeque;
    std::stack<int>     iStack;
    std::queue<int>     iQueue;
    std::priority_queue<int>  iPriorityQueue;
    std::set<int>     iSet;
    std::map<int, std::string>  iMap;

    iVec   += 0, 1, 2, 3, 4, 5;
    iList   += 0, 1, 2, 3, 4, 5;
    iDeque   += 0, 1, 2, 3, 4, 5;
    iStack   += 0, 1, 2, 3, 4, 5;
    iQueue   += 0, 1, 2, 3, 4, 5;
    iPriorityQueue += 0, 1, 2, 3, 4, 5;
    iSet   += 0, 1, 2, 3, 4, 5;
    insert(iMap)
     ( 1 , "one" )
     ( 2 , "two" )
     ( 3 , "three" )
     ( 4 , "four" )
     ( 5 , "five" );

    out << std::string(consoleWidth, '=') << newline_if_not_console
     << "STL Test..." << std::endl
     << std::string(consoleWidth, '=') << newline_if_not_console;

    out << "Native Array   = " <<  iDoubleArray << std::endl;
    out << "vector         = " << iVec   << std::endl;
    out << "list           = " << iList   << std::endl;
    out << "deque          = " << iDeque   << std::endl;
    out << "queue          = " << iQueue   << std::endl;
    out << "stack          = " << iStack   << std::endl;
    out << "priority_queue = " << iPriorityQueue << std::endl;
    out << "set            = " << iSet   << std::endl;
    out << "map            = " << iMap   << std::endl;

    out << std::string(consoleWidth, '=') << std::endl;
}

void Boost_test_ostream(std::ostream& out)
{
    out << std::string(consoleWidth, '=') << newline_if_not_console
    << "Boost Test..."  << std::endl
    << std::string(consoleWidth, '=') << newline_if_not_console;

}

int main()
{
    std::ofstream stl("STL_test_ostream.txt"),
       boost("Boost_test_ostream.txt");

    STL_test_ostream(std::cout);
    Boost_test_ostream(std::cout);

    STL_test_ostream(stl);
    Boost_test_ostream(boost);
}

I haven't wrote the code for Boost containers yet. Hopefully, I'll do it sometime :)

All what you have to do, is to include this file["streamer.hpp"]:

#ifndef DATASTRUCTRE_STREAMER
#define DATASTRUCTRE_STREAMER

#include <stack>
#include <queue>
#include <boost/array.hpp>
#include <functional>
#include <memory>

namespace streamer
{

    // one-value data structure streaming function
    template <class Container, class Stream>
    Stream& printOneValueContainer(Stream& outputstream, const Container& container)
    {
     Container::const_iterator beg = container.begin();

     outputstream << "[";

     while(beg != container.end())
     {
      outputstream << " " << *beg++;
     }

     outputstream << " ]";

     return outputstream;
    }

    // pair-value data structure streaming function
    template <class Container, class Stream>
    Stream& printPairValueContainer(Stream& outputstream, const Container& container)
    {
     Container::const_iterator beg = container.begin();

     outputstream << "[";

     while(beg != container.end())
     {
      outputstream << " " << "<" << beg->first << " , " << beg->second << ">";
      beg++;
     }

     outputstream << " ]";

     return outputstream;
    }



    /*
    *************************************************************
    C++ Standard Library
    *************************************************************
    */

    // Sequence Containers.

    // vector, list, deque
    template
    < class Type
    , template<class Type, class Allocator = std::allocator<Type> > class Container
    , class Stream
    >
    Stream& operator<<(Stream& outputstream, const Container<Type>& container)
    {
     return printOneValueContainer(outputstream, container);
    }

    // Associative Containers.

    // set, multiset
    template
     < class Key
     , template<class KeyType, class Traits = std::less<KeyType>, class Allocator = std::allocator<KeyType> > class Container
     , class Stream
     >
    Stream& operator<<(Stream& outputstream, const Container<Key>& container)
    {
     return printOneValueContainer(outputstream, container);
    }

    // map, multimap
    template
     < class Key, class Value
     , template<class KeyType, class ValueType, class Traits = std::less<KeyType>, class Allocator = std::allocator<std::pair<const KeyType, ValueType> > > class Container
     , class Stream
     >
    Stream& operator<<(Stream& outputstream, const Container<Key, Value>& container)
    {
     return printPairValueContainer(outputstream, container);
    }

    // Adapters.

    // stack, queue
    template < class Type, class Container >
    const Container& container(const std::stack<Type, Container>& stack)
    {
     struct HackedStack : private std::stack<Type, Container>
     {
      static const Container& container(const std::stack<Type, Container>& stack)
      {
                return stack.*&HackedStack::c;
            }
        };

     return HackedStack::container(stack);
    }

    template < class Type, class Container >
    const Container& container(const std::queue<Type, Container>& queue)
    {
     struct HackedQueue : private std::queue<Type, Container>
     {
      static const Container& container(const std::queue<Type, Container>& queue)
      {
                return queue.*&HackedQueue::c;
            }
        };

     return HackedQueue::container(queue);
    }

    template
     < class Type
     , template <class Type, class Container = std::deque<Type> > class Adapter
     , class Stream
     >
    Stream& operator<<(Stream& outputstream, const Adapter<Type>& adapter)
    {
     return printOneValueContainer(outputstream, container(adapter));
    }

    // priority_queue
    template < class Type, class Container, class Compare >
    const Container& container(const std::priority_queue<Type, Container, Compare>& priorityQue)
    {
     struct HackedProiorityQueue : private std::priority_queue<Type, Container, Compare>
     {
      static const Container& container(const std::priority_queue<Type, Container, Compare>& priorityQue)
      {
                return priorityQue.*&HackedProiorityQueue::c;
            }
        };

     return HackedProiorityQueue::container(priorityQue);
    }

    template < class Type, class Container, class Compare, class Stream >
    Stream& operator<<(Stream& outputstream, const std::priority_queue<Type, Container, Compare>& adapter)
    {
     return printOneValueContainer(outputstream, container(adapter));
    }

    /*
    *************************************************************
    C++ Native Arrays
    *************************************************************
    */

    template <class Type, std::size_t size, class Stream>
    Stream& operator<<(Stream& outputstream, Type (&array)[size])
    {
     outputstream << "[";

     for(std::size_t i = 0; i < size; ++i)
     {
      outputstream << " " << array[i];
     }

     outputstream << " ]";

     return outputstream;
    }

    /*
    *************************************************************
     Boost
    *************************************************************
    */
}

#endif
AraK
Thanks for the code sample and the example. Currently I am trying not to use any external code for this. Ideally, I would like gdb to either do it natively (pretty printing has been mentioned) or make a script for gdb which help it to do so. From other responses, I am banking on the new version of gdb to be better in this respect. And, btw, I am writing my own code. Regards.