31

I have not worked on shared pointers yet .. I just know the concept. I'm trying to debug functions in the following c++ class, which stores data of an XML file (read-in via the xerces library).

// header file
class ParamNode;
typedef boost::shared_ptr<ParamNode> PtrParamNode;

class ParamNode : public boost::enable_shared_from_this<ParamNode> {
public:
   ...
   typedef enum { DEFAULT, EX, PASS, INSERT, APPEND } ActionType;
   bool hasChildren() const;
   PtrParamNode GetChildren();
   PtrParamNode Get(const std::string&  name, ActionType = DEFAULT );
protected:
   ....
   ActionType defaultAction_;
}

Now if I'm debugging a piece of code in which I have an instance of the pointer to the class ParamNode, and it's called paramNode_

PtrParamNode paramNode_;
// read xml file with xerces
paramNode_ = xerces->CreateParamNodeInstance();
// now, the xml data is stored in paramNode_.
std::string probGeo;
// this works in the code, but not in (gdb)!!
paramNode_->Get("domain")->GetValue("gt",probGeo);
cout << probGeo << endl; // <-- breakpoint HERE

Using gdb I'm inspecting the paramNode_ object:

(gdb) p paramNode_
$29 = {px = 0x295df70, pn = {pi_ = 0x2957ac0}}
(gdb) p *paramNode_.px
$30 = {
  <boost::enable_shared_from_this<mainclass::ParamNode>> = {weak_this_ = {px = 0x295df70, pn = {pi_ = 0x2957ac0}}}, 
  _vptr.ParamNode = 0x20d5ad0 <vtable for mainclass::ParamNode+16>, 
  ...
  name_= {...}, 
  children_ = {size_ = 6, capacity_ = 8, data_ = 0x2969798},
  defaultAction_ = mainclass::ParamNode::EX, }

and print its members:

(gdb) ptype *paramNode_.px
type = class mainclass::ParamNode : public boost::enable_shared_from_this<mainclass::ParamNode> {
  protected:
    ...
    mainclass::ParamNode::ActionType defaultAction_;
  public:
    bool HasChildren(void) const;
    mainclass::PtrParamNode GetChildren(void);
    mainclass::PtrParamNode Get(const std::string &, mainclass::ParamNode::ActionType);

However, I can only call the functions HasChildren or GetChildren, whereas calling Get from gdb results in an error:

(gdb) p (paramNode_.px)->HasChildren()
 $7 = true
 (gdb) p (paramNode_.px)->GetChildren()
 $8 = (mainclass::ParamNodeList &) @0x295dfb8: {
   size_ = 6, 
   capacity_ = 8, 
   data_ = 0x29697a8
  }
(gdb) p (paramNode_.px)->Get("domain")
 Cannot resolve method mainclass::ParamNode::Get to any overloaded instance
(gdb) set overload-resolution off
(gdb) p (paramNode_.px)->Get("domain")
 One of the arguments you tried to pass to Get could not be converted to what the function wants.
(gdb) p (paramNode_.px)->Get("domain", (paramNode_.px).defaultAction_)
 One of the arguments you tried to pass to Get could not be converted to what the function wants.

In the code, executing the Get("domain") function works just fine. Why is that? I'm thankful if you include explanations in your answer, due to my limited knowledge of shared pointers.

Sebastian
  • 1,408
  • 1
  • 20
  • 28
  • 1
    Maybe this has nothing to do with `shared_ptr`. Maybe `gdb` just cannot convert `"domain"` (`const char [7]`, can implicitly decay to a `const char*`) to `const std::string&` (by constructing a temporary `std::string`) at runtime. I don't have a `gdb` under the hand, but I suggest you try with a very simple code like `std::size_t f(const std::string& s) { return s.length(); }`, then in gdb `p f("hello")` and maybe `p f(std::string("hello"))`, to see if you still get the error. – gx_ May 24 '13 at 12:38
  • good idea. I just tried this. The function `f` works in the code, however, `(gdb) p f("hello") Attempt to take address of value not located in memory.` `(gdb) set overload-resolution on (gdb) p f("hsdflo") Cannot resolve function f to any overloaded instance`. Using `std:string` in gdb resulted in an syntax error... – Sebastian May 24 '13 at 12:49

4 Answers4

32

gdb is not a compiler, it will not do the (not-so-)nice user-defined type conversions for you. If you wish to call a function that wants a string, you need to give it a string, not a const char*.

Unfortunately, gdb cannot construct an std::string for you on the command line, again because it is not a compiler and object creation is not a simple function call.

So you will have to add a little helper function to your program, that would take a const char* and return an std::string&. Note the reference here. It cannot return by value, because then gdb will not be able to pass the result by const reference (it's not a compiler!) You can choose to return a reference to a static object, or to an object allocated on the heap. In the latter case it will leak memory, but this is not a big deal since the function is meant to be called only from the debugger anyway.

std::string& SSS (const char* s)
{
    return *(new std::string(s));
}

Then in gdb

gdb> p (paramNode_.px)->Get(SSS("domain"))

should work.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 2
    yes, this looks good sir. I need to supply all arguments though (the `DEFAULT` second parameter needs to be supplied as well). `(gdb) p (paramNode_.px)->Get(SSS("domain")) Too few arguments in function call.`. However, this works: `(gdb) p (paramNode_.px)->Get(SSS("domain"), (paramNode_.px).defaultAction_).px $28 = (mainclass::ParamNode *) 0x2969710`. Thanks for the detailed comments! – Sebastian May 24 '13 at 13:17
  • See also https://stackoverflow.com/questions/42462860/calling-stdbasic-string-in-gdb :-) – John H. Nov 09 '18 at 01:47
  • Wait, just want to get this straight: is gdb not a compiler? – JohnK Jan 24 '20 at 19:13
  • Actually it's possible [Creating C++ string in GDB - Stack Overflow](https://stackoverflow.com/questions/7429462/creating-c-string-in-gdb) – user202729 Dec 04 '21 at 12:11
19

In such a situation I just had success after giving the command

set overload-resolution off
rwst
  • 2,515
  • 2
  • 30
  • 36
  • 5
    It would be great if this answer could be expanded a bit further. How does setting this parameter solve the problem? – mallwright Jan 30 '18 at 10:32
  • 1
    `set overload-resolution off` "Disable overload resolution for C++ expression evaluation. For overloaded functions that are not class member functions, GDB chooses the first function of the specified name that it finds in the symbol table, whether or not its arguments are of the correct type. For overloaded functions that are class member functions, GDB searches for a function whose signature exactly matches the argument types." https://www.sourceware.org/gdb/current/onlinedocs/gdb/Debugging-C-Plus-Plus.html – Lekensteyn May 17 '19 at 00:16
13

A couple additions to the previous answer --

gdb will probably eventually learn how to do conversions like this. It can't now; but there is active work on improving support for C++ expression parsing.

gdb doesn't understand default arguments, either. This is partly a bug in gdb; but also partly a bug in g++, which doesn't emit them into the DWARF. I think DWARF doesn't even define a way to emit non-trivial default arguments.

Tom Tromey
  • 21,507
  • 2
  • 45
  • 63
5

n.m.'s answer is great, but to avoid having to edit your code and recompile take a look at the solution given in Creating C++ string in GDB.

In that solution they demonstrate allocating space for a std::string on the heap and then initializing a std::string to pass into the function they'd like to call from gdb.

CyanCoding
  • 1,012
  • 1
  • 12
  • 35