2013-05-24 14 views
19

Nie pracowałem jeszcze nad współdzielonymi wskaźnikami. Po prostu znam tę koncepcję. Próbuję debugować funkcje w następującej klasie C++, która przechowuje dane pliku XML (wczytanie za pośrednictwem biblioteki xerces).W gdb mogę wywoływać niektóre funkcje klasowe, ale inne "nie można rozwiązać". Czemu?

// 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_; 
} 

Teraz jeśli mam debugowania kawałek kodu, w którym mam instancję wskaźnik do klasy ParamNode, i to się nazywa 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 

Korzystanie gdb mam inspekcji paramNode_ obiekt:

(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, } 

i wydrukować jego członkowie:

(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); 

Mogę jednak tylko wywoływać funkcje HasChildren lub GetChildren, natomiast wywołanie Get z gdb wyniki w błąd:

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

W kodzie wykonywania funkcji Get("domain") działa dobrze. Dlaczego? Jestem wdzięczny, jeśli uwzględnisz wyjaśnienia w swojej odpowiedzi, ze względu na moją ograniczoną znajomość współdzielonych wskaźników.

+1

Może to nie ma nic wspólnego z 'shared_ptr'. Może 'gdb' po prostu nie może przekonwertować' "domain" '(' const char [7] ', może niejawnie zepsuć do' const char * ') do' const std :: string & '(przez skonstruowanie tymczasowego' std :: string ') w czasie wykonywania. Nie mam 'gdb' pod ręką, ale proponuję spróbować z bardzo prostym kodem jak' std :: size_t f (const std :: string & s) {return s.length(); } ', następnie w gdb' p f ("cześć") 'i może' p f (std :: string ("hello"))), aby sprawdzić, czy nadal pojawia się błąd. –

+0

dobry pomysł. Właśnie próbowałem tego. Funkcja 'f' działa w kodzie, jednak' (gdb) pf ("cześć") Próba pobrania adresu wartości, która nie znajduje się w pamięci. '(Gdb) ustawiono przeciążenie-rozdzielczość na (gdb) pf (" hsdflo ") Nie można rozwiązać funkcji f z żadnym przeciążonym wystąpieniem. Użycie 'std: string' w gdb spowodowało błąd składniowy ... – Sebastian

Odpowiedz

23

gdb nie jest kompilatorem, nie wykona dla ciebie (niezupełnie-) miłych konwersji typu użytkownika. Jeśli chcesz wywołać funkcję, która chce uzyskać string, musisz nadać jej numer string, a nie const char*.

Niestety gdb nie może utworzyć dla Ciebie linii poleceń z linii std::string, ponieważ nie jest to kompilator, a tworzenie obiektów nie jest prostym wywołaniem funkcji.

Musisz więc dodać do programu trochę funkcji pomocnika, która zajmie const char* i zwróci std::string&. Zanotuj tutaj odniesienie. Nie może zwrócić wartości, ponieważ wtedy gdb nie będzie mógł przekazać wyniku przez odniesienie do const (nie jest to kompilator!) Możesz wybrać, aby zwrócić odwołanie do statycznego obiektu lub do obiektu przydzielonego na stercie. W tym drugim przypadku wyciek pamięci, ale to nie jest wielka sprawa, ponieważ funkcja ma być wywołana tylko z debuggera.

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

Następnie w gdb

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

powinno działać.

+1

tak, to wygląda dobrze, proszę pana. Muszę jednak podać wszystkie argumenty (należy również podać drugi parametr "DEFAULT"). '(gdb) p (paramNode_.px) -> Get (SSS (" domena ")) Za mało argumentów w wywołaniu funkcji.". Działa to jednak: '(gdb) p (paramNode_.px) -> Get (SSS (" domena "), (paramNode_.px) .defaultAction _). Px $ 28 = (mainclass :: ParamNode *) 0x2969710'. Dzięki za szczegółowe komentarze! – Sebastian

8

Parę uzupełnienia poprzedniej odpowiedzi -

gdb będzie prawdopodobnie w końcu dowiedzieć się, jak zrobić konwersje w takim stanie. Nie może teraz; ale aktywnie pracujemy nad poprawą obsługi parsowania wyrażenia C++.

gdb nie rozumie również domyślnych argumentów. Jest to częściowo błąd w gdb; ale także częściowo błąd w g ++, który nie emituje ich do DWARF. Myślę, że DWARF nie definiuje nawet sposobu emisji nietrywialnych domyślnych argumentów.

+1

dzięki za ten dodatek. Czy znasz już jakieś debuggery, które mogą to już zrobić? – Sebastian

7

W takiej sytuacji po prostu miałem sukces po podaniu komendy

set overload-resolution off 
+0

Byłoby wspaniale, gdyby ta odpowiedź mogła zostać rozszerzona nieco dalej. W jaki sposób ustawienie tego parametru rozwiązuje problem? – allsey87

1

odpowiedź n.m. jest wielki, ale w celu uniknięcia konieczności edytowania kodu i rekompilacji spojrzeć na rozwiązania podane w Creating C++ string in GDB.

W tym roztworze wykażą Alokacja przestrzeni dla std::string na stercie, a następnie inicjowanie std::string przejść do function chcieliby połączyć się z gdb.