Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > explicit auto_ptr<T>::auto_ptr(T*) ?

Reply
Thread Tools

explicit auto_ptr<T>::auto_ptr(T*) ?

 
 
Sousuke
Guest
Posts: n/a
 
      03-15-2010
The constructor for auto_ptr<T> which takes a T* is explicit, which is
requiring me to create a temporary when passing a T* to a function
that takes an auto_ptr<T> (by value). Something like this:

void f1(auto_ptr<int> p)
{
}

void f2()
{
int* p = new int;
// I have to do either:
f1(static_cast<auto_ptr<int> >(p));
// or:
//f1(auto_ptr<int>(p));
}

In another case, I have an auto_ptr<T>, where T is a subclass of the T
of the auto_ptr parameter of the function I'm calling:

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

void f1(auto_ptr<A> p)
{
}

void f2()
{
auto_ptr<B> p(new B);
// I still have to do either:
f1(static_cast<auto_ptr<A> >(p));
// or:
//f1(auto_ptr<A>(p));
}

I would expect that by calling:
f1(p);
the template constructor of auto_ptr<T> which takes an
auto_ptr<Other>& would be called, where Other is the template
parameter and where T* is compatible with Other*. However, the
compiler says:
error C2664: 'f1' : cannot convert parameter 1 from
'std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty>'
with
[
_Ty=B
]
and
[
_Ty=A
]
No user-defined-conversion operator available that can perform
this conversion, or the operator cannot be called

Does auto_ptr have some magic to avoid the creation of a temporary in
either of these cases?
 
Reply With Quote
 
 
 
 
mzdude
Guest
Posts: n/a
 
      03-15-2010
On Mar 15, 7:49*am, Sousuke <(E-Mail Removed)> wrote:
> The constructor for auto_ptr<T> which takes a T* is explicit, which is
> requiring me to create a temporary when passing a T* to a function
> that takes an auto_ptr<T> (by value). Something like this:
>
> void f1(auto_ptr<int> p)
> {
>
> }
>

IMHO passing auto_ptr as a function parameter is usually
wrong. You are giving the function lifetime management of
the resource. You probably want
void f1(auto_ptr<A> &p) {}


> void f2()
> {
> * * int* p = new int;
> * * // I have to do either:
> * * f1(static_cast<auto_ptr<int> >(p));
> * * // or:
> * * //f1(auto_ptr<int>(p));
>
> }

Now you would write
auto_ptr<int> p(new int);
f1(p);
no extra copies and no additional casting required.

>
> In another case, I have an auto_ptr<T>, where T is a subclass of the T
> of the auto_ptr parameter of the function I'm calling:
>
> class A { public: virtual ~A() {} };
> class B : public A {};
>
> void f1(auto_ptr<A> p)
> {
>
> }

If you have control of the code perhaps
template<typename T>
void f1(auto_ptr<T> &p)
{}

>
> void f2()
> {
> * * auto_ptr<B> p(new B);
> * * // I still have to do either:
> * * f1(static_cast<auto_ptr<A> >(p));
> * * // or:
> * * //f1(auto_ptr<A>(p));
>
> }

now becomes
auto_ptr<B> p(new B);
f1(p);

>
> I would expect that by calling:
> f1(p);
> the template constructor of auto_ptr<T> which takes an
> auto_ptr<Other>& would be called, where Other is the template
> parameter and where T* is compatible with Other*. However, the
> compiler says:
> error C2664: 'f1' : cannot convert parameter 1 from
> 'std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty>'
> * * * * with
> * * * * [
> * * * * * * _Ty=B
> * * * * ]
> * * * * and
> * * * * [
> * * * * * * _Ty=A
> * * * * ]
> * * * * No user-defined-conversion operator available that can perform
> this conversion, or the operator cannot be called
>
> Does auto_ptr have some magic to avoid the creation of a temporary in
> either of these cases?


 
Reply With Quote
 
 
 
 
Sousuke
Guest
Posts: n/a
 
      03-15-2010
On Mar 15, 11:13*am, mzdude <(E-Mail Removed)> wrote:
> On Mar 15, 7:49*am, Sousuke <(E-Mail Removed)> wrote:> The constructor for auto_ptr<T> which takes a T* is explicit, which is
> > requiring me to create a temporary when passing a T* to a function
> > that takes an auto_ptr<T> (by value). Something like this:

>
> > void f1(auto_ptr<int> p)
> > {

>
> > }

>
> IMHO passing auto_ptr as a function parameter is usually
> wrong. You are giving the function lifetime management of
> the resource. You probably want
> void f1(auto_ptr<A> &p) {}


But the point of using auto_ptr instead of a plain pointer in the
first place is that it explicitly states that the function takes
ownership of the passed pointer (not to mention that it deletes the
pointer at the end of the function and makes the code exception-safe).
Passing an auto_ptr<T>& doesn't do any of those things.

>
> > void f2()
> > {
> > * * int* p = new int;
> > * * // I have to do either:
> > * * f1(static_cast<auto_ptr<int> >(p));
> > * * // or:
> > * * //f1(auto_ptr<int>(p));

>
> > }

>
> Now you would write
> * * auto_ptr<int> p(new int);
> * * f1(p);
> no extra copies and no additional casting required.
>
>
>
> > In another case, I have an auto_ptr<T>, where T is a subclass of the T
> > of the auto_ptr parameter of the function I'm calling:

>
> > class A { public: virtual ~A() {} };
> > class B : public A {};

>
> > void f1(auto_ptr<A> p)
> > {

>
> > }

>
> If you have control of the code perhaps
> template<typename T>
> void f1(auto_ptr<T> &p)
> {}
>
>
>
> > void f2()
> > {
> > * * auto_ptr<B> p(new B);
> > * * // I still have to do either:
> > * * f1(static_cast<auto_ptr<A> >(p));
> > * * // or:
> > * * //f1(auto_ptr<A>(p));

>
> > }

>
> now becomes
> * *auto_ptr<B> p(new B);
> * *f1(p);


That sort of solves the problem if the function takes an auto_ptr<T>&
(a reference), but I don't think that's a good idea.

Anyway, I think I'll have to settle with the temporary

>
>
>
>
>
> > I would expect that by calling:
> > f1(p);
> > the template constructor of auto_ptr<T> which takes an
> > auto_ptr<Other>& would be called, where Other is the template
> > parameter and where T* is compatible with Other*. However, the
> > compiler says:
> > error C2664: 'f1' : cannot convert parameter 1 from
> > 'std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty>'
> > * * * * with
> > * * * * [
> > * * * * * * _Ty=B
> > * * * * ]
> > * * * * and
> > * * * * [
> > * * * * * * _Ty=A
> > * * * * ]
> > * * * * No user-defined-conversion operator available that can perform
> > this conversion, or the operator cannot be called

>
> > Does auto_ptr have some magic to avoid the creation of a temporary in
> > either of these cases?

 
Reply With Quote
 
mzdude
Guest
Posts: n/a
 
      03-15-2010
On Mar 15, 1:22*pm, Sousuke <(E-Mail Removed)> wrote:
> But the point of using auto_ptr instead of a plain pointer in the
> first place is that it explicitly states that the function takes
> ownership of the passed pointer (not to mention that it deletes the
> pointer at the end of the function and makes the code exception-safe).
> Passing an auto_ptr<T>& doesn't do any of those things.
>


auto_ptr does document who owns the resource. I think whenever
possible
whoever creates the resource should release the resource. It is
expected behaviour.

Ex 1:
auto_ptr<int> p(new int);
f1(p);

is just as exception safe as

Ex 2:
int *p = new int;
f1(auto_ptr<int>(p));

The difference is under maintenance someone may
try to use p at a later date. Which of course leads
to undefined behaviour since the memory was released.

I see no advantage to Ex 2 and there are definitely
obfucsation issues. Although I have no data to back it
up, I think Ex 1 is more idiomatic C++.

if you are really concerned about scoping then
Ex 1a:
{
auto_ptr<int> p(new int);
f1(p);
}

now the resource is given up on the completion of f1().


> void f2()
> {
> auto_ptr<B> p(new B);
> // I still have to do either:
> f1(static_cast<auto_ptr<A> >(p));
> // or:
> //f1(auto_ptr<A>(p));
> }



A quick quesition. Just after f1() returns back to f2() is
p still pointing to a valid object? If you have to think about
this, then reconsider the interface.

 
Reply With Quote
 
mzdude
Guest
Posts: n/a
 
      03-15-2010
On Mar 15, 1:20*pm, Juha Nieminen <(E-Mail Removed)> wrote:
> mzdude wrote:
> > IMHO passing auto_ptr as a function parameter is usually
> > wrong. You are giving the function lifetime management of
> > the resource. You probably want
> > void f1(auto_ptr<A> &p) {}

>
> * That still doesn't guarantee that the function won't transfer the
> ownership, though... This might even change if the function is modified
> later, breaking the calling code.


nothing would ever guarantee that it won't break under maintenance.
But it
is less likely if common coding conventions are followed.

>
> * At least when passing by value the behavior is consistent (ie. the
> ownership is always transferred).


The behaviour is consistent, but my IMHO too many contortions are
required by the calling code for no additional benefits. The code
is not more secure, and the object life time is exactly the same.

>
> --- news://freenews.netfront.net/ - complaints: (E-Mail Removed) ---


 
Reply With Quote
 
Sousuke
Guest
Posts: n/a
 
      03-15-2010
On Mar 15, 12:58*pm, mzdude <(E-Mail Removed)> wrote:
> On Mar 15, 1:22*pm, Sousuke <(E-Mail Removed)> wrote:
>
> > But the point of using auto_ptr instead of a plain pointer in the
> > first place is that it explicitly states that the function takes
> > ownership of the passed pointer (not to mention that it deletes the
> > pointer at the end of the function and makes the code exception-safe).
> > Passing an auto_ptr<T>& doesn't do any of those things.

>
> auto_ptr does document who owns the resource. I think whenever
> possible
> whoever creates the resource should release the resource. It is
> expected behaviour.


In my actual code this isn't really possible (or practical, anyway).
The 'f1' function actually looks like:

void DecoratorArray::Add(auto_ptr<PrefixDecorator> decorator)
{
m_prefixDecorators.push_back(decorator.get());
decorator.release();
}

where m_prefixDecorators is a private member of DecoratorArray
declared like this:

vector<PrefixDecorator*> m_prefixDecorators;

and where PrefixDecorator is an abstract class.

Whoever adds objects to an instance of this "array" class forgets
about them (until they are needed again, at which time another method
in DecoratorArray is called to access them). Finally, they are deleted
by DecoratorArray's destructor:

DecoratorArray::~DecoratorArray()
{
for (vector<PrefixDecorator*>::iterator iter =
m_prefixDecorators.begin(); iter != m_prefixDecorators.end(); ++iter)
delete *iter;
// some more code...
}

> Ex 1:
> * auto_ptr<int> p(new int);
> * f1(p);
>
> is just as exception safe as
>
> Ex 2:
> * *int *p = new int;
> * *f1(auto_ptr<int>(p));
>
> The difference is under maintenance someone may
> try to use p at a later date. Which of course leads
> to undefined behaviour since the memory was released.


In some places (those where I need to manipulate the pointer prior to
adding it to the array) I'm doing what Ex 1 does. In other places I
just do:

f1(auto_ptr<int>(new int));

but I wish I could avoid the temporary by just doing:

f1(new int);

> I see no advantage to Ex 2 and there are definitely
> obfucsation issues. Although I have no data to back it
> up, I think Ex 1 is more idiomatic C++.
>
> if you are really concerned about scoping then
> Ex 1a:
> * {
> * * auto_ptr<int> p(new int);
> * * f1(p);
> * }
>
> now the resource is given up on the completion of f1().


But the intent is that f1 should take on the ownership of the passed
pointer.

> > void f2()
> > {
> > * * auto_ptr<B> p(new B);
> > * * // I still have to do either:
> > * * f1(static_cast<auto_ptr<A> >(p));
> > * * // or:
> > * * //f1(auto_ptr<A>(p));
> > }

>
> A quick quesition. Just after f1() returns back to f2() is
> p still pointing to a valid object?


Nope; f1 takes ownership.

> If you have to think about
> this, then reconsider the interface.

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-15-2010
On Mar 15, 11:49 am, Sousuke <(E-Mail Removed)> wrote:
> The constructor for auto_ptr<T> which takes a T* is explicit,
> which is requiring me to create a temporary when passing a T*
> to a function that takes an auto_ptr<T> (by value).


Whether a conversion is implicit or explicit doesn't change
anything with regards to temporaries. Depending on the context,
making a conversion implicit reduces the number of characters
you have to type, and increases the risk of error and the
probability of ambiguity. Generally, the balance weighs against
implicit conversions (but I'm not so sure here).

> Something like this:


> void f1(auto_ptr<int> p)
> {
> }


> void f2()
> {
> int* p = new int;
> // I have to do either:
> f1(static_cast<auto_ptr<int> >(p));
> // or:
> //f1(auto_ptr<int>(p));
> }


And?

> In another case, I have an auto_ptr<T>, where T is a subclass
> of the T of the auto_ptr parameter of the function I'm
> calling:


> class A { public: virtual ~A() {} };
> class B : public A {};


> void f1(auto_ptr<A> p)
> {
> }


> void f2()
> {
> auto_ptr<B> p(new B);
> // I still have to do either:
> f1(static_cast<auto_ptr<A> >(p));
> // or:
> //f1(auto_ptr<A>(p));
> }


> I would expect that by calling:
> f1(p);
> the template constructor of auto_ptr<T> which takes an
> auto_ptr<Other>& would be called, where Other is the template
> parameter and where T* is compatible with Other*.


This is what I would expect too. If I read the standard
correctly, it's also what the standard requires; the converting
constructor:
template<typename Y> auto_ptr(auto_ptr<Y>&) throw();
is not explicit.

> However, the compiler says:
> error C2664: 'f1' : cannot convert parameter 1 from
> 'std::auto_ptr<_Ty>' to 'std::auto_ptr<_Ty>'
> with
> [
> _Ty=B
> ]
> and
> [
> _Ty=A
> ]
> No user-defined-conversion operator available that can perform
> this conversion, or the operator cannot be called


It's hard to say. It may be a bug in the compiler, but auto_ptr
has undergone a number of changes in time, and it's possible
that the library simply isn't up to date.

> Does auto_ptr have some magic to avoid the creation of a
> temporary in either of these cases?


Again: having an implicit conversion doesn't eliminate the
temporary. And making it explicit doesn't create an additional
temporary.

--
James Kanze

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-15-2010
On Mar 15, 7:00 pm, Juha Nieminen <(E-Mail Removed)> wrote:
> mzdude wrote:


[...]
> If the function is taking an auto_ptr as parameter, there
> ought to be a reason for that. Usually if it takes an auto_ptr
> as parameter, it means it *wants* ownership of the object, and
> auto_ptr achieves exactly that. It makes little sense to give
> it an object using an auto_ptr otherwise.


The usual reason for using auto_ptr as a parameter is not for
memory management per se; it's that the calling code no longer
has the right to access the pointed to object. I use auto_ptr
extensively in my threading interfaces---once you've passed the
object to another thread, you'd better not access it, because if
you do, a race condition will result.

--
James Kanze
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-15-2010
On Mar 15, 5:58 pm, mzdude <(E-Mail Removed)> wrote:
> On Mar 15, 1:22 pm, Sousuke <(E-Mail Removed)> wrote:


> > But the point of using auto_ptr instead of a plain pointer
> > in the first place is that it explicitly states that the
> > function takes ownership of the passed pointer (not to
> > mention that it deletes the pointer at the end of the
> > function and makes the code exception-safe). Passing an
> > auto_ptr<T>& doesn't do any of those things.


> auto_ptr does document who owns the resource. I think whenever
> possible whoever creates the resource should release the
> resource.


Not really. Most of the time, when whoever creates the resource
should release it, there are even simpler solutions, like
scoped_ptr. You use auto_ptr explicitly when this is not the
case. (Or, of course, when you have auto_ptr, but not
scoped_ptr.) Most of the time, if whoever creates the
resource should free it, you shouldn't be using dynamic
allocation to begin with (but there are a lot of exceptions).

--
James Kanze
 
Reply With Quote
 
Bart van Ingen Schenau
Guest
Posts: n/a
 
      03-16-2010
On Mar 15, 12:49*pm, Sousuke <(E-Mail Removed)> wrote:
> The constructor for auto_ptr<T> which takes a T* is explicit, which is
> requiring me to create a temporary when passing a T* to a function
> that takes an auto_ptr<T> (by value). Something like this:


The temporary has to be created anyway. Either explicitly by you or
implicitly by the compiler.
That the auto_ptr<T>::auto_ptr(T*) constructor is explicit is a good
thing, because it prevents you from writing stuf like this without any
warning that it will blow-up at runtime:

void f1(auto_ptr<int> p);
//...
void f2()
{
int i;

f1(&i); // Is this correct? No, but only a warning because the
constructor is explicit.
}

Bart v Ingen Schenau
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Explicit instantiation of STL vector demands explicit instantiation of all the templates it using internally. krunalbauskar@gmail.com C++ 1 12-25-2006 03:51 PM
What's the difference betwwen explicit instantiaion and explicit specialization? Andy C++ 5 01-30-2005 11:46 PM
signal handlers: does %SIG{'CLD'} require explicit SA_NOCLDSTOP via POSIX funcs? steffen staehle Perl 0 09-07-2004 03:22 PM
Is explicit template qualification required for explicit delete? J.T. Conklin C++ 1 08-11-2004 02:06 AM
How can I set Option Explicit systematically in VB.Net? Eric Mamet ASP .Net 2 10-16-2003 11:56 PM



Advertisments