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

Discussion in 'C++' started by Sousuke, Mar 15, 2010.

  1. Sousuke

    Sousuke Guest

    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?
    Sousuke, Mar 15, 2010
    #1
    1. Advertising

  2. Sousuke

    mzdude Guest

    On Mar 15, 7:49 am, Sousuke <> 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?
    mzdude, Mar 15, 2010
    #2
    1. Advertising

  3. Sousuke

    Sousuke Guest

    On Mar 15, 11:13 am, mzdude <> wrote:
    > On Mar 15, 7:49 am, Sousuke <> 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?
    Sousuke, Mar 15, 2010
    #3
  4. Sousuke

    mzdude Guest

    On Mar 15, 1:22 pm, Sousuke <> 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.
    mzdude, Mar 15, 2010
    #4
  5. Sousuke

    mzdude Guest

    On Mar 15, 1:20 pm, Juha Nieminen <> 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: ---
    mzdude, Mar 15, 2010
    #5
  6. Sousuke

    Sousuke Guest

    On Mar 15, 12:58 pm, mzdude <> wrote:
    > On Mar 15, 1:22 pm, Sousuke <> 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.
    Sousuke, Mar 15, 2010
    #6
  7. Sousuke

    James Kanze Guest

    On Mar 15, 11:49 am, Sousuke <> 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
    James Kanze, Mar 15, 2010
    #7
  8. Sousuke

    James Kanze Guest

    On Mar 15, 7:00 pm, Juha Nieminen <> 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
    James Kanze, Mar 15, 2010
    #8
  9. Sousuke

    James Kanze Guest

    On Mar 15, 5:58 pm, mzdude <> wrote:
    > On Mar 15, 1:22 pm, Sousuke <> 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
    James Kanze, Mar 15, 2010
    #9
  10. On Mar 15, 12:49 pm, Sousuke <> 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
    Bart van Ingen Schenau, Mar 16, 2010
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. SerGioGio

    shared_ptr vs std::auto_ptr

    SerGioGio, Jul 3, 2003, in forum: C++
    Replies:
    3
    Views:
    5,434
    Alexander Terekhov
    Jul 3, 2003
  2. J.T. Conklin
    Replies:
    1
    Views:
    429
    David Hilsee
    Aug 11, 2004
  3. Siemel Naran

    auto_ptr<Derived> to auto_ptr<Base>

    Siemel Naran, Jan 10, 2005, in forum: C++
    Replies:
    2
    Views:
    1,534
    Dave Rahardja
    Jan 11, 2005
  4. Andy
    Replies:
    5
    Views:
    494
    Shezan Baig
    Jan 30, 2005
  5. Replies:
    1
    Views:
    559
    Salt_Peter
    Dec 25, 2006
Loading...

Share This Page