Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ pointer argument getting set to NULL just before 'ret' instruction [duplicate]

I'm having a peculiar issue. I thought I knew a decent amount of C++ but I must be overlooking some nuance?

I've got some templated classes, and essentially all that is happening is based on some condition, an object is being moved from one std::list to another.

The method of focus here is the doAndGet( T *t ). My intent is for t to come in as NULL (or whatever, I really don't care, but it should be NULL or nullptr, and if I end up moving a T element *t from myList to myOtherList, I want T *t to point to the item that was moved.

Now maybe there is something about std::list that I'm not aware of, but when stepping through my code, t gets assigned properly and—originally I thought after the method returned, but later found out that—right before the ret instruction, argument T *t gets set back to NULL

Can any guru shed some light on this issue? It's a real head-scratcher for me...

template<typename T, typename C>
class Base : IsDerivedFrom<T, C>
{
public:
    typedef std::list<T*> SpecialList;
    virtual bool doAndGet( T* t ) = 0;

protected:

    SpecialList myList;
};

template<typename T>
class Derived : public Base<T, Other>, public Other
{
public:
    Derived( void );
    virtual ~Derived( void );

    bool doAndGet( T* t );

protected:

    typename Base<T, Other>::SpecialList myOtherList;

};

template<typename T>
bool Derived<T>::doAndGet( T *t )
{
    // Nothing to process
    if (myOtherList.empty()) {return false;}

    t = (*myOtherList.begin());
    myOtherList.pop_front();

    if (true/* some condition needs to be moved */)
    {
        t->status = 1;
        this->myList.push_back(t);
        return true;
    } else
    {
        // Something bad happened...
        delete t;
        t = nullptr;
        return false;
    }
}

// Use... (pretend I defined MyOtherClass somewhere, not important)
Derived<MyOtherClass> derivedInstance;

MyOtherClass *t = nullptr;
if ( derivedInstance.doAndGet(t) )
{
    // ... Here I should expect `t` to be not `NULL` and not `nullptr`
    // This however, is not ever the case in my testing...
}
like image 372
Volte Avatar asked Feb 13 '23 18:02

Volte


1 Answers

If you want to pass in a variable to a function and have any changes within that function to be reflected back to the caller, you need to use a reference.

C++, like C, is pass by value, where a function only gets a copy of a variable. C++ has references to allow pass by reference.

In other words, your function signature should be:

bool doAndGet( T* &t );

to state that t is a reference to a T*, allowing changes to reflect back to the original pointer in the caller.

A simpler example follows:

#include <iostream>
static void change (int a, int &b) { a = b = 0; }
int main() {
    int a = 42, b = 42;
    change (a, b);
    std::cout << a << ' ' << b << '\n';
    return 0;
}

This outputs 42 0 because the a passed in is pass by value and changes are not reflected back to the caller. The b is passed in as a reference so changes are reflected back.

like image 136
paxdiablo Avatar answered Feb 15 '23 10:02

paxdiablo