Austin Hyde
Austin Hyde

Reputation: 27436

Convert "this" to a reference-to-pointer

Let's say I have a struct

struct Foo {
    void bar () {
       do_baz(this);
    }
    /* See edit below
    void do_baz(Foo*& pFoo) {
       pFoo->p_sub_foo = new Foo; // for example
    }
    */

    Foo* p_sub_foo;
}

GCC tells me that

temp.cpp: In member function ‘void Foo::bar()’:
temp.cpp:3: error: no matching function for call to ‘Foo::do_baz(Foo* const)’
temp.cpp:5: note: candidates are: void Foo::do_baz(Foo*&)

So, how do I convert what is apparently a const Foo* to a Foo*&?

EDIT: I didn't use a very good example. do_baz should read

void do_baz(Foo*& pFoo) {
    if (pFoo == NULL) {
        pFoo = new Foo;
        return;
    }
    //other stuff
    do_baz(pFoo->p_sub_foo);
    //more stuff
}

Upvotes: 5

Views: 5002

Answers (4)

Michael Aaron Safyan
Michael Aaron Safyan

Reputation: 95489

Give the variable a name, and then you will have a pointer reference type:

void bar () {
   Foo* me = this;
   do_baz(me);
}

I should also point out that your do_baz function isn't making use of the fact that its parameter is a reference (you are not assigning to the pointer, itself, only to what is being pointed to by the pointer). Consequently, it really makes more sense to change the type of the parameter to Foo* instead of Foo*&, or to make it a Foo&, in which case you would use dot (.) instead of arrow (->) when dereferencing the parameter's member.

Edit
Your new version of do_baz now makes use of the fact that the parameter is a reference. The solution above (simply using a named pointer) will still work for your new version of the problem. That said, I would advise against what you are doing. It seems you are trying to insert an element at the end of a linked list...

Firstly, I would advise that if you are implementing a linked list that you maintain not only a pointer to the first node in the list, but also a pointer to the last node in the list at all times, so that insertion at the end of the list may be performed in constant-time. If, however, that is not a possibility, I would nevertheless advise you to use an iterative implementation rather than a recursive one as it is cleaner and simpler. It would look like:

Foo* current=this;
while (current->next != NULL){
    current=current->next;
}
current->next = new Foo;

Upvotes: 4

AnT stands with Russia
AnT stands with Russia

Reputation: 320401

You can't.

Firstly, this is not necessarily a const Foo *. this would be a const Foo * is a const method of the class Foo. In a non-const method this is just Foo *. (Actually your error message mentions Foo* const. Where did you see const Foo *?)

Secondly, and more importantly, this is not an lvalue. You can't have a pointer to this. You can't have a non-constant reference to this. The only thing that you can have is a const reverence to this, i.e. a reference of type Foo *const &.

It (Foo *const &) will work in your case.

void do_baz(Foo* const& pFoo) { 
   pFoo->p_sub_foo = new Foo;
} 

But I don't see the point of all this. Just declare a normal Foo * pointer as parameter for your do_baz method

void do_baz(Foo* pFoo) { 
   pFoo->p_sub_foo = new Foo;
} 

and get the same result. What do you think you need that reference for?

EDIT: Taking into account your edit, what you are trying to do cannot be done with a single do_baz function, since in the first call you'd potentially (semantically) attempt to modify this, which is impossible (even if the modifying code will never be executed in practice). Whether you want it or not, you can't have a non-const reference to this, even if you don't intend to write anything through it. You'll probably have to implement the very first call with a different function

void do_baz(Foo*& pFoo) { 
  if (pFoo == NULL) { 
    pFoo = new Foo; 
    return; 
  } 
  //other stuff 
  do_baz(pFoo->p_sub_foo); 
  //more stuff 
} 

void do_baz_root(Foo* pFoo) { 
  assert(pFoo != NULL);
  //other stuff 
  do_baz(pFoo->p_sub_foo); 
  //more stuff 
} 

and then make the first call as

void bar() {
  do_baz_root(this);
}

Upvotes: 7

Michael Burr
Michael Burr

Reputation: 340188

The keyword this is not an lvalue so this can't be assigned to/changed (regardless of whether what it points to is const or not). In other words, you might be able to change what this points to, but you can't change the value of this itself. The C++ standard 9.3.2 "The this pointer":

In the body of a nonstatic (9.3) member function, the keyword this is a non-lvalue expression

Only const references can bind to non-lvalue objects, so you'd need to bind it to a Foo* const& if you want to bind the this pointer to a reference.

Change the signature of the function to:

void do_baz(Foo* const& pFoo);

Upvotes: 0

greyfade
greyfade

Reputation: 25647

You don't.

this is a Foo* const, meaning it is a const pointer to a non-const Foo. Your reference is non-const, so the correct declaration would be a Foo* const &.

But it doesn't make any sense to do this, so don't.

Upvotes: 0

Related Questions