"alg" <al******@yahoo .com> wrote in message news:<85******* **************@ bgtnsc04-news.ops.worldn et.att.net>...
I am learning to use "auto_ptr" and found that the following 2 line would
not compile:
auto_ptr<Cat> pCat;
pCat = new Cat(6);
until I changed it to the one:
auto_ptr<Cat> pCat(new Cat(6));
People have already given the correct reason (there is no implicit
conversion from T* to auto_ptr<T>); I will give you the reason as
there are some people here who would be glad to see it I think. I know
that a month ago (before reading Josuttis) I would have. So anyway:
Because auto_ptr is a smart pointer, it will take "ownership" of the
pointer. This is what it's made for, therefor it is usually a good
thing. However, sometimes it can be easy to give an auto_ptr ownership
when you don't want to or don't realize it.
You'll notice that the following also will (should) not compile:
auto_ptr<Cat> pCat = new Cat(6);
Note that this is different than the two examples you use above,
especially the first. A statement such as the above will call a
one-argument constructor, not the default constructor and then an
assignment. Thus the above call is *almost* the same as
auto_ptr<Cat> pCat(new Cat(6));
The only difference is that in the first example there is an implicit
conversion from Cat* to auto_ptr<Cat>, while the second example has an
explicit conversions.
Normally implicit conversions are well and good, for instance it's
very nice to be able to say
string s = "Hello world!";
which is an implicit conversion from const char* to string. As another
example,
double abs(double arg)
{ return (arg>0) ? arg : -arg; }
c = abs(14);
is also an implicit conversion from an integer (14) to a double. (For
the record, I don't know if that's the actual signature of a standard
version of abs, but we'll go with it at least.) It'd be kind of a pain
to have to write
c = abs(double(14)) ;
instead. (Actually, 14.0 would be better there, but that would of
course not work with variables.) However, implicit conversions can be
a source of problems in certain cases, which comes up a lot with
auto_ptrs.
For instance, consider what would happen if you pass a smart pointer
to a function:
template<typena me T>
void foo(auto_ptr<T> uhoh)
{ }
the argument uhoh takes posession of the passed object which is then
destroyed when the function exits. Meanwhile your client code
Cat *c = new Cat;
foo(c);
calls foo, perhaps not realzing that foo takes an auto_ptr, or not
realizing the semantics of auto_ptr, or you think you're calling a
different function, or whatever. In any case, a temporary
auto_ptr<Cat> is created that points to *c, it's passed to the
function which takes ownership of it in the form of uhoh, the function
goes out of scope, uhoh is destructed which deletes the Cat object,
and the function returns. You then go to try to use c some more
c->Purr(Cat::loud ly);
but the Cat c points to is now deleted! (I'm not sure if auto_ptr sets
the pointer to null; a quick look at Josuttis seems to indicate it
doesn't, but I'm not sure.)
What is much better is for implicit conversions to be ruled out. The
way this is done is to specify the constructor as explicit, as in
explicit auto_ptr(T* ptr = 0);
(this is the actual relivant constructor according to Josuttis minus
the throw();). The explicit keyword gurantees that mistakes like the
above con't be made. It requires
auto_ptr<Cat> apc(new Cat(9));
Cat *c = new Cat(9);
foo(auto_ptr<Ca t>(c)); // note the explicit cast
instead of
auto_ptr<Cat> apc = new Cat(9);
Cat *c = new Cat(9);
foo(c); // note the explicit cast
While from what I've seen it seems that most of the problems could
come from one-argument constructors being called implicitly, there are
I'm sure similar problems with assignment operators allowing
assignment of T* directly, so this is why it isn't allowed.