N
Noah Roberts
Keith said:(just-kidding(
Hmm ... interesting you changed "colleague" to "boss".
I misread
I wonder if
Keith said:(just-kidding(
Hmm ... interesting you changed "colleague" to "boss".
Yannick said:I have written "delete this" but I certainly would not classify it as
typical either. Certainly, some specific problems can have a very
elegant solution using "delete this" but I see it as one possible
solution to limited set of situations.
James said:Do they? boost::shared_ptr certainly doesn't.
James said:But that's irrelevant, since they don't provide the interface or
the services of a pointer.
Noah said:#include <iostream>
#include <boost/shared_ptr.hpp>
struct test_object
{
~test_object() { std::cout << "object deleted\n"; }
};
int main()
{
boost::shared_ptr<test_object> ptr(new test_object);
ptr.reset(); // delete the object explicitly
std::cout << "post reset\n"; // to demonstrate it wasn't scope.
}
Sure they do.
When applied to a particular use of pointers: as addresses to
arrays, the std::vector object very much does provide this
service.
Any function that accepts a pointer to T and then
treats that pointer as an array can be modified to accept a
std::vector simply by changing the parameter. However, it
does this "smartly" and there is much more information
available from the std::vector than there is from the pointer.
There is no smart pointer that can or should provide ALL the
services a pointer can be used to provide.
And I've seen it used too much and debugged too much code that
used it. MUCH care need be taken when you do a delete this.
For one, you better have that constructor protected so naive
coders don't think it's part of the public interface and just
try to use it.
In general, I don't like the idea of an object being
responsible for its own lifetime.
There are always exceptions to any general rule, so before the
pedants tear into me for saying so: yes, there are exceptions.
In general though, an object should have one responsibility
only and if all an object is responsible for is its own
lifetime...then it has no reason to exist.
Despite the relative publicity around reference counted
pointers, I personally, think that the standard commitee got
it right when they pick auto_ptr for their only (first?) smart
pointer. I find passing of ownership more often useful than
refence counting. But I certainly wouldn't classified them as
"least useful"Since you are coming out so strongly against boost:shared_ptr,
would you mind giving examples of other types of pointers you
find more useful and clarify why you feel boost:shared_ptr
have so little usefulness in them.
The one I use most is std::auto_ptr. Second (but a very distant
second) is my own reference counted pointer, which is invasive.
Application specific smart pointers are probably more frequent
than either of these, but it's each time a different pointer
type.
Boost::shared_ptr has a very serious flaw: you can't create two
of them from the same raw pointer without getting into trouble.
And of course, the pointer you have most frequently access to is
the this pointer, and that it a raw pointer. Which makes
boost::shared_ptr extremely error prone (for managing
lifetime---I have no problems with using it with an explicit
deleter that doesn't terminate the lifetime of the object).
For boost::shared_ptr to be used safely for object lifetime
management, cycles must be impossible (i.e. the pointed to
object contains no pointers), and all pointers to the object
must be boost::shared_ptr (including the this pointer). Since
the first condition is not all that frequent, and the second is
impossible in C++, the only reasonable solution is to ban the
class (again, when used for object lifetime management).
#include <iostream>
#include <boost/shared_ptr.hpp>
struct test_object
{
~test_object() { std::cout << "object deleted\n"; }
};
int main()
{
boost::shared_ptr<test_object> ptr(new test_object);
ptr.reset(); // delete the object explicitly
std::cout << "post reset\n"; // to demonstrate it wasn't scope.
}
James said:There must be some degree of misunderstanding here.
Obviously.
One of the advantages of smart pointers is that
you can't use pointer arithmetic on them.
James said:I suspect that there's a typo in there somewhere---you *never*
use delete this in a constructor. For the rest, delete this
doesn't require more care than any other delete.
Oh really? Well, let's try out this code:
struct an_object
{
void f() { delete this; }
};
void some_function()
{
an_object x;
x.f();
}
That's only true of a subset of smart pointers. Since all
iterators are smart pointers the count of such that support
(nay, are built for) pointer arithmetic in the standard vastly
outnumber the ones that do not...even C++0x.
A smart pointer provides some subset of the functionality of
raw pointers and limits and/or extends the interface to
provide for a particular use case.
Oh really? Well, let's try out this code:
struct an_object
{
void f() { delete this; }
};
void some_function()
{
an_object x;
x.f();
}
Indeed. Or even make the constructor private and force the use of
factories.
Factory functions have their uses, but not for ensuring dynamic allocation.
Oh, this is very interesting for me... in another thread - which went
deserted, for my delusion - I suggested factories exactly to ensure
dynamic allocation.
So then, you guys have understood which kind of programmer I happen to
be, haven't you? ;-)
Alf, could you please point me on the right direction about ensuring
that a class never gets instantiated as a local object?
Thank you very much.
* Francesco:
See my example up-thread.
I discuss the issues (also how to do other such things, related) in more detail
in my old "Pointers" tutorial.
Alf said:* Noah Roberts:
I guess your point is that some more care is required for 'delete this'
than for 'delete that', namely, taking care not to access any members
afterwards, which can be more of a problem when one is currently within
a member routine.
However your example does not illustrate that, it only illustrates the
usual dangers of 'delete' that apply irrespective of the context.
One way to design the class so that it's more safe wrt. the usual
dangers is as follows:
class AnObject
{
protected:
virtual ~AnObject() {}
public:
void f() { delete this; }
};
void someFunc()
{
AnObject x; // Compilation error, must be new'ed.
x.f();
}
Alf said:* Yannick Tremblay:
I have never seen the great attraction of the factory approach.
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.