Smart Pointer new/Forwarding Problem Solved (by Force)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
39 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Smart Pointer new/Forwarding Problem Solved (by Force)

David Abrahams

I've developed some facilities that perhaps ought to be developed into
full-fledged libraries or components of existing Boost libraries.
This work centers around my long-standing threat to build a library
that could create smart pointers safely, without ever exposing a raw
pointer to the user.  For example,

  #include <memory>
  #include <boost/shared_ptr.hpp>
  #include "new.hpp"

  struct foo
  {
    foo(int&, char const*, std::auto_ptr<int> const&);
  };

  std::auto_ptr<int> x(new_<int>(3));
  std::auto_ptr<foo> y(new_<foo>(*x, "hello, world", x));
  boost::shared_ptr<foo> z(new_<foo>(*x, (char const*)"hello, world", x));


To solve this problem correctly, it was necessary to address "the
forwarding problem"
(http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm).  To
that end, I developed some preprocessor macros that one can use to
generate the necessary overload sets.  Is there interest in adopting
any of this code (enclosed), and if so, where should it go?


// Copyright David Abrahams 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PP_IS_ITERATING

# ifndef NEW_DWA2006324_HPP
#  define NEW_DWA2006324_HPP

#  include "forward.hpp"

#  include <boost/preprocessor/iteration/iterate.hpp>
#  include <boost/preprocessor/repetition/enum_params.hpp>
#  include <boost/preprocessor/seq/for_each.hpp>

#  include <memory>

#  ifndef BOOST_NEW_MAX_ARITY
#   define BOOST_NEW_MAX_ARITY 5
#  endif

template <class T>
std::auto_ptr<T> new_()
{
    return std::auto_ptr<T>(new T);
}

# define BOOST_PP_ITERATION_PARAMS_1 (3, (1, BOOST_NEW_MAX_ARITY, "new.hpp"))
# include BOOST_PP_ITERATE()

# endif // NEW_DWA2006324_HPP

#elif BOOST_PP_ITERATION_DEPTH() == 1

// Generate the first few iterations using vertical repetition.  This
// method is about twice as slow on G++ as using horizontal
// repetition, but more debuggable.
# if BOOST_PP_ITERATION() < 4

# define BOOST_PP_ITERATION_PARAMS_2 (3, (0, (1 << BOOST_PP_ITERATION()) - 1, "new.hpp"))
# include BOOST_PP_ITERATE()

# else

// Generate later iterations using horizontal repetition.
#  define NEW_arity BOOST_PP_ITERATION()
#  define BOOST_FORWARD_new(r, ignored, constness_seq)                          \
template <class T, BOOST_PP_ENUM_PARAMS_Z(1, NEW_arity, class A) >            \
std::auto_ptr<T> new_( BOOST_FORWARD_ENUM_BINARY_PARAM_SEQ_R(r, constness_seq, A, x) )  \
{                                                                               \
    return std::auto_ptr<T>(new T(BOOST_PP_ENUM_PARAMS_Z(1, NEW_arity, x)));  \
}

BOOST_PP_SEQ_FOR_EACH(BOOST_FORWARD_new, ~, BOOST_FORWARD_BINARY_SEQ(BOOST_PP_ITERATION()))
#  undef NEW_arity
   
# endif

#elif BOOST_PP_ITERATION_DEPTH() == 2

# define NEW_arity BOOST_PP_FRAME_ITERATION(1)
# define NEW_binary BOOST_FORWARD_BINARY_SEQ(NEW_arity)

# define NEW_constness BOOST_PP_SEQ_ELEM(BOOST_PP_ITERATION(), NEW_binary)

template <class T, BOOST_PP_ENUM_PARAMS_Z(1, NEW_arity, class A) >
std::auto_ptr<T> new_( BOOST_FORWARD_ENUM_BINARY_PARAM_SEQ_R(1, NEW_constness, A, x) )
{
    return std::auto_ptr<T>(new T(BOOST_PP_ENUM_PARAMS_Z(1, NEW_arity, x)));
}

# undef NEW_arity
# undef NEW_binary
# undef NEW_constness

#endif

// Copyright David Abrahams 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_FORWARD_DWA2006324_HPP
# define BOOST_FORWARD_DWA2006324_HPP

# include <boost/preprocessor/seq/seq.hpp>
# include <boost/preprocessor/seq/elem.hpp>
# include <boost/preprocessor/seq/for_each_product.hpp>
# include <boost/preprocessor/seq/for_each_i.hpp>
# include <boost/preprocessor/control/while.hpp>
# include <boost/preprocessor/control/expr_iif.hpp>
# include <boost/preprocessor/comparison/not_equal.hpp>
# include <boost/preprocessor/punctuation/comma_if.hpp>

// Generates a Boost.Preprocessor Sequence representing all the binary
// numbers from 0 to 2^n-1.  Each element of the result is an
// n-element Sequence whose elements are 1s and 0s. For example,
//
//   BOOST_FORWARD_BINARY_SEQ(2)
//
// generates
//
//   ((0)(0)) ((0)(1)) ((1)(0)) ((1)(1))
//
# define BOOST_FORWARD_BINARY_SEQ(n)            \
    BOOST_PP_SEQ_ELEM(                          \
        1                                       \
      , BOOST_PP_WHILE(                         \
          BOOST_FORWARD_SEQ_HEAD_NONZERO        \
        , BOOST_FORWARD_COUNT_BINARY            \
        , (n)( (BOOST_PP_SEQ_NIL) )             \
      )                                         \
    )

// More efficient version of the same macro that can be used when the
// re-entrancy depth is known.
# define BOOST_FORWARD_BINARY_SEQ_D(d,n)        \
    BOOST_PP_SEQ_ELEM(                          \
        1                                       \
      , BOOST_PP_WHILE_##d(                     \
          BOOST_FORWARD_SEQ_HEAD_NONZERO        \
        , BOOST_FORWARD_COUNT_BINARY            \
        , (n)( (BOOST_PP_SEQ_NIL) )             \
      )                                         \
    )

// A predicate for use with BOOST_PP_WHILE that is true iff the head
// of seq is nonzero
# define BOOST_FORWARD_SEQ_HEAD_NONZERO(r, seq) \
    BOOST_PP_SEQ_ELEM(0, seq)

// Update state for BOOST_FORWARD_BINARY_SEQ(_D).
//
// Requires: state is a Sequence of the form (n)( binary ) where n is
// a remaining number of iterations and binary is a Sequence whose
// elements BOOST_PP_SEQ_NIL or are themselves Sequences of 1s and 0s.
//
// Generates: a new Sequence of the form (n)( binary01 ) where
// binary01 is a sequence consisting of the cross-product of binary
// with (0)(1).
# define BOOST_FORWARD_COUNT_BINARY(r, state)       \
    (BOOST_PP_DEC(BOOST_PP_SEQ_HEAD(state)))        \
        (BOOST_PP_SEQ_FOR_EACH_PRODUCT_R(           \
             r                                      \
           , BOOST_FORWARD_COMPOSE_BINARY           \
           , BOOST_PP_SEQ_TAIL(state)((0)(1))  ) )

# define BOOST_FORWARD_COMPOSE_BINARY(r, elements) \
    (BOOST_PP_SEQ_ELEM(0,elements)(BOOST_PP_SEQ_ELEM(1,elements)))

# define BOOST_FORWARD_BINARY_PARAM(r, names, i, elem)   \
    BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0,names),i) BOOST_PP_EXPR_IIF(elem,const) & BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names),i)

# define BOOST_FORWARD_ENUM_BINARY_PARAM_SEQ(constness_seq, type_name, param_name)   \
    BOOST_PP_SEQ_FOR_EACH_I(BOOST_FORWARD_BINARY_PARAM,(type_name)(param_name), constness_seq)

# define BOOST_FORWARD_ENUM_BINARY_PARAM_SEQ_R(r, constness_seq, type_name, param_name)              \
    BOOST_PP_SEQ_FOR_EACH_I_R(r, BOOST_FORWARD_BINARY_PARAM,(type_name)(param_name), constness_seq)


#endif



--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

Vaclav Vesely
David Abrahams wrote:

> I've developed some facilities that perhaps ought to be
> developed into full-fledged libraries or components of
> existing Boost libraries.
> This work centers around my long-standing threat to build a
> library that could create smart pointers safely, without ever
> exposing a raw pointer to the user.  For example,
>
>   #include <memory>
>   #include <boost/shared_ptr.hpp>
>   #include "new.hpp"
>
>   struct foo
>   {
>     foo(int&, char const*, std::auto_ptr<int> const&);
>   };
>
>   std::auto_ptr<int> x(new_<int>(3));
>   std::auto_ptr<foo> y(new_<foo>(*x, "hello, world", x));
>   boost::shared_ptr<foo> z(new_<foo>(*x, (char const*)"hello,
> world", x));
>
> To solve this problem correctly, it was necessary to address
> "the forwarding problem"
> (http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
> ).  To that end, I developed some preprocessor macros that
> one can use to generate the necessary overload sets.  Is
> there interest in adopting any of this code (enclosed), and
> if so, where should it go?

Yes, I'm interested.

IMHO maximum arity of about 5 isn't too restrictive. Except of this I would
like to have an alternative new_ with greater arity which use only const
reference forwarding. Non-const referrence parameters can be explicitly
wrapped with boost::ref.

I'm confused with syntax. new_<T> always creates auto_ptr<T>. How can I
create for example shared_ptr<T>?

How this is related to auto_overhead?

Regards,
Vaclav


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

Ulrich Eckhardt-2
On Wednesday 29 March 2006 08:05, Václav Veselý wrote:
> I'm confused with syntax. new_<T> always creates auto_ptr<T>. How can I
> create for example shared_ptr<T>?

You probably can't, but:
 - std::auto_ptr is much less resource intensive (shared_ptr requires an
additionally, dynamically-allocated structure to hold some internals)
 - you don't need to, as auto_ptr converts to shared_ptr, there is a special
ctor taking an auto_ptr

Uli
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

Phil Nash-2
In reply to this post by David Abrahams
David Abrahams wrote:

> I've developed some facilities that perhaps ought to be developed into
> full-fledged libraries or components of existing Boost libraries.
> This work centers around my long-standing threat to build a library
> that could create smart pointers safely, without ever exposing a raw
> pointer to the user.  For example,
>
>   #include <memory>
>   #include <boost/shared_ptr.hpp>
>   #include "new.hpp"
>
>   struct foo
>   {
>     foo(int&, char const*, std::auto_ptr<int> const&);
>   };
>
>   std::auto_ptr<int> x(new_<int>(3));
>   std::auto_ptr<foo> y(new_<foo>(*x, "hello, world", x));
>   boost::shared_ptr<foo> z(new_<foo>(*x, (char const*)"hello, world", x));
>
>
> To solve this problem correctly, it was necessary to address "the
> forwarding problem"
> (http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm).  To
> that end, I developed some preprocessor macros that one can use to
> generate the necessary overload sets.  Is there interest in adopting
> any of this code (enclosed), and if so, where should it go?

First, I'd like to say that I am very interested in this in a general
way, as I frequently end up writing forwarding sets (although usually
escape the forwarding problem).

I'm not intimate with the pp library, but if I read your code correctly
you have "solved the forwarding problem" by writing all the permutations
of const and non const for each forwarding set. Is that correct? If not
could you clarify for us non-PPers?

Personally I don't like the "new_" name. but that's purely subjective. I
think I'd prefer something more like, "atomic_new" (although that could
also be a bit misleading), or that at least has something more
descriptive to indicate what else is going on, other than just a bare
trailing _.

What about the array form?

Would it be worth going as far as to add static functions to the boost
smart pointer classes that do the same thing, and even hidding their raw
pointer constructors away so they can only be created using the safer
factory methods? Obviously that last step would break existing code, but
it would only break the largely unsafe uses.

Best regards,

[)o
IhIL..
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

Larry Evans
In reply to this post by David Abrahams
On 03/28/2006 05:45 PM, David Abrahams wrote:
> I've developed some facilities that perhaps ought to be developed into
> full-fledged libraries or components of existing Boost libraries.
> This work centers around my long-standing threat to build a library
> that could create smart pointers safely, without ever exposing a raw
> pointer to the user.  For example,
[snip]
>   std::auto_ptr<foo> y(new_<foo>(*x, "hello, world", x));
>   boost::shared_ptr<foo> z(new_<foo>(*x, (char const*)"hello, world", x));

My interpretation of "create smart pointers safely" is that there's no
way the user can "accidentally" create a smart pointer which
"originally" was a raw pointer.  Since shared_ptr has a CTOR taking a
raw pointer, this doesn't make shared_ptr "safe".  OTOH, even if
the raw pointer CTOR of shared_ptr were removed, there would still be
the shared_ptr CTOR taking an auto_ptr, and since auto_ptr can be
constructed from a raw pointer, this still would not make share_ptr
"safe" since "origin" of the shared_ptr could come from a raw pointer.

AFAICT, the only way a smart pointer can be made "safe" (as defined
above) is to only allow CTOR arguments which are "safe" (w.r.t. raw
pointer origination) themselves.  And the only way to do that is
provide a template class having a merge of the properties of
auto_ptr and new_, IOW, it's derived from auto_ptr or contains
an auto_ptr, and the CTOR interface is like the new_ CTOR interface.
e.g. like the auto_overhead I'd mentioned before.

Or maybe I'm misunderstanding your definition of "safe"?

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

Paul Mensonides
> -----Original Message-----
> From: [hidden email]
> [mailto:[hidden email]] On Behalf Of Larry Evans

> Or maybe I'm misunderstanding your definition of "safe"?

One way that it is safer is in sequence points, e.g.

f( shared_ptr<X>(new X(1, 2, 3)), shared_ptr<Y>(new Y(1, 2, 3)) );

f( make_shared_ptr<X>(1, 2, 3), make_shared_ptr<Y>(1, 2, 3) );

The latter is safe, whereas the former is not.

Regards,
Paul Mensonides

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

David Abrahams
In reply to this post by Larry Evans
Larry Evans <[hidden email]> writes:

> On 03/28/2006 05:45 PM, David Abrahams wrote:
>> I've developed some facilities that perhaps ought to be developed into
>> full-fledged libraries or components of existing Boost libraries.
>> This work centers around my long-standing threat to build a library
>> that could create smart pointers safely, without ever exposing a raw
>> pointer to the user.  For example,
> [snip]
>>   std::auto_ptr<foo> y(new_<foo>(*x, "hello, world", x));
>>   boost::shared_ptr<foo> z(new_<foo>(*x, (char const*)"hello, world", x));
>
> My interpretation of "create smart pointers safely" is that there's no
> way the user can "accidentally" create a smart pointer which
> "originally" was a raw pointer.  Since shared_ptr has a CTOR taking a
> raw pointer, this doesn't make shared_ptr "safe".  

...

> Or maybe I'm misunderstanding your definition of "safe"?

Deliberately, it seems.  I didn't say I was ``making shared_ptr
"safe".''  I said I was making it possible to create smart pointers
safely.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

David Abrahams
In reply to this post by Vaclav Vesely
Václav Veselý <[hidden email]> writes:

> Yes, I'm interested.
>
> IMHO maximum arity of about 5 isn't too restrictive. Except of this I would
> like to have an alternative new_ with greater arity which use only const
> reference forwarding. Non-const referrence parameters can be explicitly
> wrapped with boost::ref.
>
> I'm confused with syntax. new_<T> always creates auto_ptr<T>. How can I
> create for example shared_ptr<T>?

auto_ptr<T> is convertible to shared_ptr<T>, so the intention was that
you would use that conversion.  I have another version where you write

    new_<shared_ptr<T> >(....)

but that just seemed syntactically heavy to little real benefit.

> How this is related to auto_overhead?

I have no idea.  Nobody ever explained auto_overhead to me in a way
that I could understand.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

David Abrahams
In reply to this post by Ulrich Eckhardt-2
Ulrich Eckhardt <[hidden email]> writes:

> On Wednesday 29 March 2006 08:05, Václav Veselý wrote:
>> I'm confused with syntax. new_<T> always creates auto_ptr<T>. How can I
>> create for example shared_ptr<T>?
>
> You probably can't, but:
>  - std::auto_ptr is much less resource intensive (shared_ptr requires an
> additionally, dynamically-allocated structure to hold some internals)
>  - you don't need to, as auto_ptr converts to shared_ptr, there is a special
> ctor taking an auto_ptr

Unfortunately for this particular facility, the converting constructor
is explicit, so you can't do

   f(new_<T>(a, b, c))

if f takes a shared_ptr<T>.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

David Abrahams
In reply to this post by Phil Nash-2
Phil Nash <[hidden email]> writes:

> First, I'd like to say that I am very interested in this in a general
> way, as I frequently end up writing forwarding sets (although usually
> escape the forwarding problem).
>
> I'm not intimate with the pp library, but if I read your code correctly
> you have "solved the forwarding problem" by writing all the permutations
> of const and non const for each forwarding set. Is that correct? If not
> could you clarify for us non-PPers?

That is correct.

> Personally I don't like the "new_" name. but that's purely subjective. I
> think I'd prefer something more like, "atomic_new" (although that could
> also be a bit misleading), or that at least has something more
> descriptive to indicate what else is going on, other than just a bare
> trailing _.

Come up with a better name and I'll consider it.

> What about the array form?

IMO it's not a very important use case, but if we have to support it,
it would have accept the T[N] form and return shared_array:

   new_<int[50]>();

interestingly, I think there's only a viable zero-argument form for
this ctor, so forwarding may not be of interest (?)

> Would it be worth going as far as to add static functions to the
> boost smart pointer classes that do the same thing,

Yes.

> and even hidding their raw pointer constructors away so they can
> only be created using the safer factory methods?

Probably not.

> Obviously that last step would break existing code, but it would
> only break the largely unsafe uses.

Except for the few safe ones :(

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

Larry Evans
In reply to this post by David Abrahams
On 03/29/2006 07:12 AM, David Abrahams wrote:
> Václav Veselý <[hidden email]> writes:
[snip]
>>How this is related to auto_overhead?
>
>
> I have no idea.  Nobody ever explained auto_overhead to me in a way
> that I could understand.
>
It's the class template version of your function template, new_.
IOW, it's something like:

   template<class T>
   struct auto_new
     : private std::auto_ptr<T>
   {
       typedef std::auto_ptr<T> super_type;
       template< BOOST_PP_ENUM_PARAMS_Z(1, NEW_arity, class A) >
       auto_new( BOOST_FORWARD_ENUM_BINARY_PARAM_SEQ_R(1, NEW_constness,
A, x) )
         : super_type(new T(BOOST_PP_ENUM_PARAMS_Z(1, NEW_arity, x)))
       {
       }
       T* get(void) { return super_type::get();}
   };

(I may have misplaced a '(' or ',' or two.  I hope you can see what
I meant).

Note there's no T* in any CTOR arguments (unless, of course, there's
some T CTOR taking a T*).

Also note, there's no Overhead<T> as there is in auto_overhead, but
that's just another feature (designed to save the extra allocation
needed shared_ptr) and wouldn't be relevant to this discussion, AFAICT.

Is auto_overhead still unclear?
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

Phil Nash-2
In reply to this post by David Abrahams
David Abrahams wrote:
> Phil Nash <[hidden email]> writes:

>> What about the array form?
>
> IMO it's not a very important use case, but if we have to support it,
> it would have accept the T[N] form and return shared_array:
>
>    new_<int[50]>();
>
> interestingly, I think there's only a viable zero-argument form for
> this ctor, so forwarding may not be of interest (?)

Very true. For me, at least, that does kinda remove the need.

>> Would it be worth going as far as to add static functions to the
>> boost smart pointer classes that do the same thing,
>
> Yes.
>
>> and even hidding their raw pointer constructors away so they can
>> only be created using the safer factory methods?
>
> Probably not.
>
>> Obviously that last step would break existing code, but it would
>> only break the largely unsafe uses.
>
> Except for the few safe ones :(

I see that Larry has been talking about much the same thing.
It wouldn't be the first time that boost has changed an interface to
make it safer, even though it breaks older code. I suppose the
difference is that the smart pointers are probably the most used classes
  of the whole of boost!

It could be done in stages, with the raw pointer and maybe auto_ptr
constructors retained but deprecated, and later removed. Not sure if
that helps much.


In any case, it would need to be put to some vote once some concrete
proposals are in place. I'd still urge you not to rule it out at this stage.

Thanks and regards,

[)o
IhIL..
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

thorsten.ottosen
In reply to this post by Paul Mensonides
Paul Mensonides wrote:

>>-----Original Message-----
>>From: [hidden email]
>>[mailto:[hidden email]] On Behalf Of Larry Evans
>
>
>>Or maybe I'm misunderstanding your definition of "safe"?
>
>
> One way that it is safer is in sequence points, e.g.
>
> f( shared_ptr<X>(new X(1, 2, 3)), shared_ptr<Y>(new Y(1, 2, 3)) );
>
> f( make_shared_ptr<X>(1, 2, 3), make_shared_ptr<Y>(1, 2, 3) );
>
> The latter is safe, whereas the former is not.

Another great example of exception-unsafe code is

std::map<std::string,boost::shared_ptr<T>> m;
m["foo"] = boost::shared_ptr<T>( new T );

-Thorsten
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

David Abrahams
In reply to this post by Phil Nash-2
Phil Nash <[hidden email]> writes:

> David Abrahams wrote:
>> Phil Nash <[hidden email]> writes:
>
>>> What about the array form?
>>
>> IMO it's not a very important use case, but if we have to support it,
>> it would have accept the T[N] form and return shared_array:
>>
>>    new_<int[50]>();
>>
>> interestingly, I think there's only a viable zero-argument form for
>> this ctor, so forwarding may not be of interest (?)
>
> Very true. For me, at least, that does kinda remove the need.
>
>>> Would it be worth going as far as to add static functions to the
>>> boost smart pointer classes that do the same thing,
>>
>> Yes.

Oh, but wait: this could introduce a lot of code duplication.  It
would probably be better to make the new free function a friend if you
want to do something like that.

>>> and even hidding their raw pointer constructors away so they can
>>> only be created using the safer factory methods?
>>
>> Probably not.
>>
>>> Obviously that last step would break existing code, but it would
>>> only break the largely unsafe uses.
>>
>> Except for the few safe ones :(
>
> I see that Larry has been talking about much the same thing.
> It wouldn't be the first time that boost has changed an interface to
> make it safer, even though it breaks older code. I suppose the
> difference is that the smart pointers are probably the most used classes
>   of the whole of boost!
>
> It could be done in stages, with the raw pointer and maybe auto_ptr
> constructors retained but deprecated, and later removed. Not sure if
> that helps much.
>
> In any case, it would need to be put to some vote once some concrete
> proposals are in place. I'd still urge you not to rule it out at this stage.

It's not up to me; I don't maintain the smart pointer library.


--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

David Abrahams
In reply to this post by David Abrahams
David Abrahams <[hidden email]> writes:

> Ulrich Eckhardt <[hidden email]> writes:
>
>> On Wednesday 29 March 2006 08:05, Václav Veselý wrote:
>>> I'm confused with syntax. new_<T> always creates auto_ptr<T>. How can I
>>> create for example shared_ptr<T>?
>>
>> You probably can't, but:
>>  - std::auto_ptr is much less resource intensive (shared_ptr requires an
>> additionally, dynamically-allocated structure to hold some internals)
>>  - you don't need to, as auto_ptr converts to shared_ptr, there is a special
>> ctor taking an auto_ptr
>
> Unfortunately for this particular facility, the converting constructor
> is explicit, so you can't do
>
>    f(new_<T>(a, b, c))
>
> if f takes a shared_ptr<T>.

I just realized we could probably fix this by removing an "explicit"
from the ctor that accepts an rvalue auto_ptr.  What about that,
Peter?  This seems like a poster child for rvalue distinction!

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

Peter Dimov
David Abrahams wrote:

> David Abrahams <[hidden email]> writes:
>
>> Unfortunately for this particular facility, the converting
>> constructor is explicit, so you can't do
>>
>>    f(new_<T>(a, b, c))
>>
>> if f takes a shared_ptr<T>.
>
> I just realized we could probably fix this by removing an "explicit"
> from the ctor that accepts an rvalue auto_ptr.  What about that,
> Peter?  This seems like a poster child for rvalue distinction!

Done.
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

Larry Evans
In reply to this post by Paul Mensonides
On 03/29/2006 06:44 AM, Paul Mensonides wrote:

>>[mailto:[hidden email]] On Behalf Of Larry Evans
>
>>Or maybe I'm misunderstanding your definition of "safe"?
>
> One way that it is safer is in sequence points, e.g.
>
> f( shared_ptr<X>(new X(1, 2, 3)), shared_ptr<Y>(new Y(1, 2, 3)) );
>
> f( make_shared_ptr<X>(1, 2, 3), make_shared_ptr<Y>(1, 2, 3) );
>
> The latter is safe, whereas the former is not.

THanks, thar clears things up.  I guess I should have remembered
that post that started all this from Vaclav with subject:

   [shared_ptr] Best Practices - new_shared_ptr

and that cited:

   http://www.gotw.ca/gotw/056.htm

The phrase "exeption safe" would have helped my memory.  I guess
exception safety is why you use "sequence points" above, although
I'm not very exception safe aware; so, I could be wrong.  Maybe I
should read more carefully Sutter's _Exceptional C++_ ?



_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

Fernando Cacciola
In reply to this post by David Abrahams
David Abrahams wrote:

> David Abrahams <[hidden email]> writes:
>
>> Ulrich Eckhardt <[hidden email]> writes:
>>
>>> On Wednesday 29 March 2006 08:05, Václav Veselý wrote:
>>>> I'm confused with syntax. new_<T> always creates auto_ptr<T>. How
>>>> can I create for example shared_ptr<T>?
>>>
>>> You probably can't, but:
>>>  - std::auto_ptr is much less resource intensive (shared_ptr
>>> requires an additionally, dynamically-allocated structure to hold
>>>  some internals) - you don't need to, as auto_ptr converts to
>>> shared_ptr, there is a special ctor taking an auto_ptr
>>
>> Unfortunately for this particular facility, the converting
>> constructor
>> is explicit, so you can't do
>>
>>    f(new_<T>(a, b, c))
>>
>> if f takes a shared_ptr<T>.
>
Then isn't it worth generalizing new_<> to all sorts of smart pointer and
handles?

Like:

 f( new_< any_smart_ptr<T> >(a, b, c)) ;

As long as there's a way to get the 'element_type' from 'any_smart_ptr'
it'll work.

On top of that there could be the friendlier: make_auto_ptr,
make_shared_ptr, etc...


--
Fernando Cacciola
SciSoft
http://fcacciola.50webs.com/






_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

David Abrahams
In reply to this post by Peter Dimov
"Peter Dimov" <[hidden email]> writes:

> David Abrahams wrote:
>> David Abrahams <[hidden email]> writes:
>>
>>> Unfortunately for this particular facility, the converting
>>> constructor is explicit, so you can't do
>>>
>>>    f(new_<T>(a, b, c))
>>>
>>> if f takes a shared_ptr<T>.
>>
>> I just realized we could probably fix this by removing an "explicit"
>> from the ctor that accepts an rvalue auto_ptr.  What about that,
>> Peter?  This seems like a poster child for rvalue distinction!
>
> Done.

Cool!  Just in case it wasn't obvious: we should do this across all
the smart pointers.  It looks like scoped_ptr could use the same
treatment, for example.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: Smart Pointer new/Forwarding Problem Solved (by Force)

thorsten.ottosen
In reply to this post by Fernando Cacciola
Fernando Cacciola wrote:

> David Abrahams wrote:
>
>>David Abrahams <[hidden email]> writes:
>>
>>
>>>Ulrich Eckhardt <[hidden email]> writes:
>>>
>>>
>>>>On Wednesday 29 March 2006 08:05, Václav Veselý wrote:
>>>>
>>>>>I'm confused with syntax. new_<T> always creates auto_ptr<T>. How
>>>>>can I create for example shared_ptr<T>?
>>>>
>>>>You probably can't, but:
>>>> - std::auto_ptr is much less resource intensive (shared_ptr
>>>>requires an additionally, dynamically-allocated structure to hold
>>>> some internals) - you don't need to, as auto_ptr converts to
>>>>shared_ptr, there is a special ctor taking an auto_ptr
>>>
>>>Unfortunately for this particular facility, the converting
>>>constructor
>>>is explicit, so you can't do
>>>
>>>   f(new_<T>(a, b, c))
>>>
>>>if f takes a shared_ptr<T>.
>>
> Then isn't it worth generalizing new_<> to all sorts of smart pointer and
> handles?
>
> Like:
>
>  f( new_< any_smart_ptr<T> >(a, b, c)) ;

this might be worth persuing (see below)

> As long as there's a way to get the 'element_type' from 'any_smart_ptr'
> it'll work.
>
> On top of that there could be the friendlier: make_auto_ptr,
> make_shared_ptr, etc...

That would generate *a lot* of code to parse for the compiler.

It is better that new_<T>(...) produces an unspecified type
that has a templated conversion operator, eg.:

template< class T >
struct new_return
{
    std::auto_ptr<T> new_;

    new_return( T* new_ ) : new_(new_)
    { }

    template< class SP >
    operator SP() const
    {
      return SP( new_.release() );
    }

    operator std::auto_ptr<T>() const
    {
      return new_;
    }
};

Or something

-Thorsten
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
12