Is it safe to create an object pointer in the stack indirectly?

Asked

Viewed 171 times

5

My class has a method that returns a pointer to itself, and at some point I use the following :

void classequalquer::metodo() {
    ClasseA * ponteiro = ClasseA().getThis();
    //usa o ponteiro nesse método sem usar delete
}

//Para referências
ClasseA* ClasseA::getThis() {
    return this;
}
  • Rodrigo, for you to have a more accurate answer, provide an example of code than ClasseA().getThis() returns, because as already explained well in the answer you had, the "security" of this will depend on how the allocated pointer is being manipulated beyond this code snippet.

3 answers

5


The excerpt posted is not safe:

void classequalquer::metodo() {
  ClasseA * ponteiro = ClasseA().getThis();
  //deferenciar o ponteiro aqui é comportamento indefinido
  //o objeto não existe mais
}

ponteiro takes the address of an object created as temporary for the assignment operation. The object is not available at the end of the sequential point ending the operation, and ponteiro invalid address reference. It’s illegal to take the address of a rvalue.


Returning the pointer through a method is safe:

Despite the passage posted, returning the pointer through a method is safe, and the excerpt should be adapted to the following form:

void classequalquer::metodo() {
  ClasseA A;
  ClasseA * ponteiro = A.getThis();
  //usa o ponteiro nesse método sem usar delete
  //o objeto ainda existe
}

But the method is unnecessary (and I personally discourage you), any code scope that has access to ClasseA::getThis() also has access to the operator &, that has return address function:

void classequalquer::metodo() {
  ClasseA A;
  ClasseA * ponteiro = &A;
}

Something similar, returning a reference to you, is quite common:

Something very similar to returning a pointer to you is quite used, as in the overload of assignment operators, where a reference to the object itself is returned (created through the de-referencing of the this), for example:

ClasseA& ClasseA::operator = (ClasseA const & outra) {
  //..(algumas operações de atribuição)..
  return *this; //semelhante a retornar ponteiro, (refere-se a este objeto)
                //mas a referência é mais transparente.
                //assim como o ponteiro, 
                //  a referência será invalidada quando o objeto for destruído
}
  • 1

    I was going to answer this question, but I didn’t because I couldn’t produce an error in Visual Studio 2005 with a simple test... but the purpose of the comment is to say that the "Classea A()" statement above does not declare an instance of Class A, and yes a function called A that returns an instance of Classea...is a situation known as "the Most vexing parse" in C++

  • @Joséx. Then my answer is wrong! Would you care to elaborate an answer? I vote for you and I delete mine. Or edit here where I comment on his excerpt?

  • 1

    calm, my friend...I totally agree with you that using a pointer to a temporary object causes undefined behavior...the remark on "the Most vexing parse" was an additional remark, which is unrelated to the question asked by the OP

  • @Joséx. I corrected the statement. It’s correct now, thank you!

2

Example showing the undefined behavior when using the resource used by OP.

// arquivo ptrtest.cpp

#include <iostream>
using namespace std;

class A
{
   public:
      int x;
      A();
      A* getThis() { return this; }
};

A::A()
{
   cout << "* this=" << (void*)this << '\n';
   x = 42;
   cout << "* &A::x=" << (void*)&x << '\n';
}

int main()
{
   A* aPtr;
   aPtr = A().getThis();
   int z = 1;
   cout << "* &aPtr= " << (void*)&aPtr << '\n';
   cout << "* &z=    " << (void*)&z << '\n';
   cout << "* A::x=  " << aPtr->x << '\n';
}

Compiling the above code in gcc 6.3.1 with the command line

g++ -O3 -o ptrtest ptrtest.cpp

(Option -O3 optimizes the generated code).

When executing, the result is:

* this=0x7ffdd82e7550
* &A::x=0x7ffdd82e7550
* &aPtr= 0x7ffdd82e7558
* &z=    0x7ffdd82e7550
* A::x=  1

Note that the variable A::x was overwritten by the value of z.

Compiling without optimization:

g++ -o ptrtest ptrtest.cpp

When executing, the result is now:

* this=0x7ffdd82e7550
* &A::x=0x7ffdd82e7550
* &aPtr= 0x7ffdd82e7558
* &z=    0x7ffdd82e7550
* A::x=  42

Note that variable A::x now nay was overwritten by the value of z.

This demonstrates that using addresses of temporary values has undefined behavior. In this case, depending on the compilation options the program displays different behaviors. The effects could be more drastic, as the program present address exception, or stay in loop, etc, whichever behavior could happen (according to the definition of language), because this is the definition of indefinite behavior: in principle, anything can happen.

1

Depends what you do with the pointer.

The object is being created in stack, this you already know. Therefore the pointer will reference a position in the stack. When this function ends, the object ceases to exist, there can no longer be a reference to it. But the reference created there also goes, so ok. But what if you missed the reference to some object by throwing the pointer at it and that object survives longer than this function? You will be accessing an object that no longer exists. And I don’t know what’s worse, give an error, or seem to work in various scenarios, but not at all.

I wouldn’t have to use the delete if you didn’t use a new.

Now if by chance the getThis() return another object created on heap, There you have to manage it, but it doesn’t seem to be the case.

  • getThis literally is 'Return this'

  • The precautions referring to loose pointers are valid, but I think you let escape that the object (in the code posted) does not last until the end of the function, but is destroyed at the end of the expression.

  • @Kahler is true, that gives answer at dawn. When I answered I did not have all information available.

  • And I made a mistake in the code of my answer. Joseph X. corrected me.

  • 1

    @Kahler I think the same as him, I do not consider his answer wrong, only it was not at the exact point. Now I think it was perfect.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.