possibility to forbid use of "this"?

  • Thread starter Ernst Murnleitner
  • Start date
E

Ernst Murnleitner

Dear Readers,

Is it possible to forbid conversion from this or use of this in general
except where it is explicitly wanted?

Reason:

I changed my program from using normal pointers to classes A, ...

typedef A * APtr;

to a shared pointer

typedef boost::shared_ptr<A> APtr;

Now, it crashes because of statements like this

// call
DoSomething(this);

.....
// implementation
void DoSomething(APtr a)
{
// do nothing with a
}

Obviously, "this" is converted to a shared ptr locally. Outside the function
DoSomething() the shared ptr is destroyed and hence it tries to delete the
class where "this" points, too. This is clearly not wanted.

Greetings,
Many thanks in advance

Ernst
 
T

tom_usenet

Dear Readers,

Is it possible to forbid conversion from this or use of this in general
except where it is explicitly wanted?

Reason:

I changed my program from using normal pointers to classes A, ...

typedef A * APtr;

to a shared pointer

typedef boost::shared_ptr<A> APtr;

Now, it crashes because of statements like this

// call
DoSomething(this);

....
// implementation
void DoSomething(APtr a)
{
// do nothing with a
}

That shouldn't compile - the constructor of shared_ptr taking a T* is
explicit, so a pointer can't implicitly convert to a shared_ptr.
Obviously, "this" is converted to a shared ptr locally. Outside the function
DoSomething() the shared ptr is destroyed and hence it tries to delete the
class where "this" points, too. This is clearly not wanted.

You have a few choices, depending on what DoSomething does. If
DoSomething doesn't hold onto a reference to a, then you can change it
to:

void DoSomething(A& aref)
{
}

If it does hold onto a reference to a, but you know it will release
that reference before a is destroyed (which you probably can't
guarantee), then you could do:

struct null_deleter
{
void operator()(void const *) const
{
}
};

//...

DoSomething(APtr(this, null_deleter()));

The safe approach is to make a shared_ptr from the this pointer. This
is only possible if the A object was created as a shared_ptr in the
first place. Follow the instructions here:
http://www.boost.org/libs/smart_ptr/sp_techniques.html#from_this

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 
R

Ron Natalie

Ernst Murnleitner said:
DoSomething() the shared ptr is destroyed and hence it tries to delete the
class where "this" points, too. This is clearly not wanted.

shared_pointer(T*) isn't declared explicit? Seems like it ought to be.
 
E

Ernst Murnleitner

That shouldn't compile - the constructor of shared_ptr taking a T* is
explicit, so a pointer can't implicitly convert to a shared_ptr.

With gcc 2.95 it compiles:

// -------------------------------------
#include <iostream.h>

#include <stdlib.h>

#include <boost/shared_ptr.hpp>



class A;

typedef boost::shared_ptr<A> APtr;

class A {

public:

A(){};

virtual ~A(){};

virtual void f(){func(this); };

void func(APtr p) {cout << "func(APtr)" << std::endl;};

};

int main(int argc, char *argv[])

{

A a;

a.f();

return EXIT_SUCCESS;

}

// -------------------------------------
 
E

Ernst Murnleitner

Ron Natalie said:
shared_pointer(T*) isn't declared explicit? Seems like it ought to be.
At least with the old gcc 2.95 it need not! But I tried it with gcc 3.3 also
and at least there was the expected error.

(I still use the gcc 2.95 as the gcc 3.3 needs 20times longer for certain
source files).

Greetings
Ernst
 
T

tom_usenet

With gcc 2.95 it compiles:

That's a shame - you should upgrade. It suspect it fails with all of
the compilers I have (GCC 3.2, Comeau C++ 4.3, VC 7.1, VC 6?), since
it is non-standard.

With this change:
#include <iostream.h>
to
#include <iostream>
using namespace std;

Comeau gives this error:

"main.cpp", line 22: error: no suitable constructor exists to convert
from
"A *" to "boost::shared_ptr<A>"
virtual void f(){func(this); };

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 
C

Chris Theis

Ernst Murnleitner said:
At least with the old gcc 2.95 it need not! But I tried it with gcc 3.3 also
and at least there was the expected error.


(I still use the gcc 2.95 as the gcc 3.3 needs 20times longer for certain
source files).

However, I´d recommend using gcc 3.3 and you probably might want to go
through your code for unnecessary compile time dependencies.

Regards
Chris
 
E

Ernst Murnleitner

The library now contains a enable_shared_from_this<>() function. You might
look up http://www.boost.org/libs/smart_ptr/sp_techniques.html

I found this just before. Now I wonder if it is possible to use

shared_from_this();

during construction of an object. I want to use it in the base class and
only store it in a std::vector. It would be used only after complete
construction but is needed during construction, as childs are constructed
from withing the constructor of the parent. The childs eventually get a
pointer to the parent for later use.

Greetings

Ernst
 
C

Chris Theis

Ernst Murnleitner said:
I found this just before. Now I wonder if it is possible to use

shared_from_this();

during construction of an object. I want to use it in the base class and
only store it in a std::vector. It would be used only after complete
construction but is needed during construction, as childs are constructed
from withing the constructor of the parent. The childs eventually get a
pointer to the parent for later use.

Greetings

Ernst

Could you give an explicit code example of what you want to do, please
because creating childs within the ctor of a base sounds very much like
flawed design to me. But I would need to see some code. Anyway, if I
understand your description correctly then there should be no problem.
Still, you should test it as I´ve not used shared_from_this() so far.

Regards
Chris
 
D

Daniel T.

Ernst Murnleitner said:
Dear Readers,

Is it possible to forbid conversion from this or use of this in general
except where it is explicitly wanted?

Reason:

I changed my program from using normal pointers to classes A, ...

typedef A * APtr;

to a shared pointer

typedef boost::shared_ptr<A> APtr;

I would call the above a bad idea. Not just because of the problem
cited, but because there is no way, in general to guarantee that all
APtr's in the original code actually point to things that must be
deleted at some point in the future. For example:

typedef A* APtr;

void foo( APtr a ) { }

int main() {
A myA;
foo( &myA );
}

is quite valid until you change the typedef...

Now if you can guarantee that all of the things held by an APtr have
actually been newed, then using a SmartPointer class that has some sort
of global way of knowing the number of references would be OK.

Of course, you still have the problem that some places in the code may
be using an A* rather than an APtr. :-(
 
E

Ernst Murnleitner

Could you give an explicit code example of what you want to do, please
because creating childs within the ctor of a base sounds very much like
flawed design to me.

A version, but without smartpointers, is at
http://control.awite.com/awitecontrol/awitecontrol-api/html/

I am currently cleaning up the source, therefore my questions. I began 2
years ago and the ioverall design didn`t need changes. However, in the
beginning I didn't use more sophisticated programming technics like design
patterns, factory classes etc.

Greetings

Ernst
 
E

Ernst Murnleitner

Now if you can guarantee that all of the things held by an APtr have
actually been newed, then using a SmartPointer class that has some sort
of global way of knowing the number of references would be OK.

Yes, I only construct them on the heap. And if I only allow a factory to
create my Objects (e.g. as Mr. Carson suggested in another message thread),
I cannot accidentally define automatic variables.
Of course, you still have the problem that some places in the code may
be using an A* rather than an APtr. :-(

OK. Can I avoid this?

The factory only delivers sthared_ptr. The only possibility to use the
poiner would be to use the shared_ptr's get().

Greetings
Ernst
 
T

tom_usenet

I found this just before. Now I wonder if it is possible to use

shared_from_this();

during construction of an object.

It isn't - the weak pointer is only initialized in the constructor of
the shared pointer, which is obviously run after the constructor of
your object.


I want to use it in the base class and
only store it in a std::vector. It would be used only after complete
construction but is needed during construction, as childs are constructed
from withing the constructor of the parent. The childs eventually get a
pointer to the parent for later use.

How are you creating your object? I suggest you use a factory, and
make the necessary extra calls after you've created the shared
pointer. e.g.

shared_ptr<YourType> make()
{
shared_ptr<YourType> ptr(new YourType);
//this was called from the YourType constructor before:
someFunc(ptr);
return ptr;
}

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 
D

Daniel T.

Ernst Murnleitner said:
Yes, I only construct them on the heap. And if I only allow a factory to
create my Objects (e.g. as Mr. Carson suggested in another message thread),
I cannot accidentally define automatic variables.

class A {
protected:
A();
};

class B: public A {
public:
B();
}

void foo( A* a );

int main() {
B b;
foo( &b );
}

How are you going to stop A's from being created on the stack again?

OK. Can I avoid this?

The factory only delivers sthared_ptr. The only possibility to use the
poiner would be to use the shared_ptr's get().

Fine, but then you must be changing the origional code rather than
simply changing a typedef from A* to shared_ptr<A>...
 
E

Ernst Murnleitner

I found this just before. Now I wonder if it is possible to use
It isn't - the weak pointer is only initialized in the constructor of
the shared pointer, which is obviously run after the constructor of
your object.

I tried: it throws an exception (and is also documented this way).

Therefore I used in the constructor of the baseclass something like this:

std::vector<shared_ptr<Base> > Base::AllItemsVector;

Base::Base(...)
{
shared_ptr<Base> p (this);
Base::AllItemsVector.push_back(p);
....
shared_ptr<Base> pChild
(Factory::NewChild("newchildname",shared_from_this()));
}

This way it seems to work. However, somewhere I read that shared_ptr cannot
be constructed in the constructor (but I cannot exactly remember). But this
seems to work.

Greetings

Ernst
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top