
Howard Hinnant wrote:
On Jan 26, 2004, at 4:59 PM, Daniel Wallin wrote:
Howard Hinnant wrote:
<snip> And I submit that: S<T[], my_deleter> is more elegant syntax than: S_array<T, my_deleter>
FWIW, I'm not sure it's a good idea to design the interface around partial specialization. std::vector<> replaces almost every possible need for array allocation, so does this use case really need to be less verbose? Is it worth dropping support for older compilers?
Need to be? No. But I still like it. <shrug> I was convinced because that's how a newbie expected it to work.
I'm starting to not like it. :-) The problem is: template<class X> void f(S_ptr<X> px); where f doesn't support arrays. A reasonably common occurence. S_array<> doesn't match, but S_ptr<T[]> does. The author of f would need to learn about enable_if to prevent array pointers from being passed to f. This is not good, although the exact degree of not-goodness is somewhat debatable.

"Peter Dimov" <pdimov@mmltd.net> wrote in messag:
Howard Hinnant wrote:
<snip> And I submit that: S<T[], my_deleter> is more elegant syntax than: S_array<T, my_deleter>
<snip>
Need to be? No. But I still like it. <shrug> I was convinced because that's how a newbie expected it to work.
I'm starting to not like it. :-) The problem is:
template<class X> void f(S_ptr<X> px);
where f doesn't support arrays. A reasonably common occurence. S_array<> doesn't match, but S_ptr<T[]> does. The author of f would need to learn about enable_if to prevent array pointers from being passed to f. This is not good, although the exact degree of not-goodness is somewhat debatable.
I'm not sure I see the problem. (Maybe because I already implemented this feature :-) If pointers to objects and pointers to arrays need different treatment, one can use: template<class X> void f(S_ptr<X> px); template<class X> void f(S_ptr<X[]> px); If one only wants to support pointers to objects, but forgets that the array case is subsumed by template<class X> void f(S_ptr<X> px); I think there will almost certianly be a compiler error if somepone tries to pass an array pointer, since the dereferencing operations are not supported. In my implementation, the user would likely be directed to something like: element_type* operator->() const { BOOST_STATIC_ASSERT(!is_array); return ptr(); } If f declares a variable of type X or X& and tries to assign to it, there will also be an error. (On VC7.1 I get the message 'array initializer needs curly braces', or 'reference to a zero-sized array is illegal') Can you think of an example where a compiler error would be undesirable, or where no error will occur until runtime? Regards, Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> writes:
If pointers to objects and pointers to arrays need different treatment, one can use:
template<class X> void f(S_ptr<X> px); template<class X> void f(S_ptr<X[]> px);
If one only wants to support pointers to objects, but forgets that the array case is subsumed by
template<class X> void f(S_ptr<X> px);
I think there will almost certianly be a compiler error if somepone tries to pass an array pointer, since the dereferencing operations are not supported.
Seriously? Why not? It seems as though dereferencing should be fine. And incidentally, upcasting should be fine, too: S_ptr<D[]> -> S_ptr<B> ;-) -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message:
"Jonathan Turkanis" <technews@kangaroologic.com>:
I think there will almost certianly be a compiler error if somepone tries to pass an array pointer, since the dereferencing operations are not supported.
Seriously? Why not?
Because it's more fun to implement that way :-)
It seems as though dereferencing should be fine. And incidentally, upcasting should be fine, too:
S_ptr<D[]> -> S_ptr<B>
;-)
Seriously, maybe this is an indictment of the concept of smart pointers to arrays. It's nice to say we want smart pointers to arrays to behave like ordinary arrays -- but ordinary arrays are really wierd! ;-) Jonathan

Jonathan Turkanis wrote:
"Peter Dimov" <pdimov@mmltd.net> wrote in messag:
Howard Hinnant wrote:
<snip> And I submit that: S<T[], my_deleter> is more elegant syntax than: S_array<T, my_deleter>
<snip>
Need to be? No. But I still like it. <shrug> I was convinced because that's how a newbie expected it to work.
I'm starting to not like it. :-) The problem is:
template<class X> void f(S_ptr<X> px);
where f doesn't support arrays. A reasonably common occurence.
S_array<>
doesn't match, but S_ptr<T[]> does. The author of f would need to
learn
about enable_if to prevent array pointers from being passed to f.
This is
not good, although the exact degree of not-goodness is somewhat
debatable.
I'm not sure I see the problem. (Maybe because I already implemented this feature :-)
If pointers to objects and pointers to arrays need different treatment, one can use:
template<class X> void f(S_ptr<X> px); template<class X> void f(S_ptr<X[]> px);
The problem is that you don't always want to have both overloads and in those cases a compiler error is very unhelpful. I can't come up with very good examples, at least not right now. But in general, disabling an overload is far better than failing to compile. Maybe Peter has some use case where this applies? -- Daniel Wallin

"Daniel Wallin" <dalwan01@student.umu.se> wrote in message news:4016A5B7.3010908@student.umu.se...
Jonathan Turkanis wrote:
"Peter Dimov" <pdimov@mmltd.net> wrote in messag:
If pointers to objects and pointers to arrays need different treatment, one can use:
template<class X> void f(S_ptr<X> px); template<class X> void f(S_ptr<X[]> px);
The problem is that you don't always want to have both overloads and in those cases a compiler error is very unhelpful. I can't come up with very good examples, at least not right now. But in general, disabling an overload is far better than failing to compile. Maybe Peter has some use case where this applies?
I almost agree. The reason that disabling overloads is better than forcing compiler errors is that you often want to allow other overloads to match. Here, if you want another overload -- or if someone else want to write one later -- no problem. If you don't, why not? Either (i) the same code works for smart pointers to objects and smart pointers to arrays, in which case there's no problem, or (ii) the code is specific to one case or the other, so a compiler error indicates a misuse of the function, which seems appropriate. Regards, Jonathan

On Jan 27, 2004, at 11:06 AM, Peter Dimov wrote:
Need to be? No. But I still like it. <shrug> I was convinced because that's how a newbie expected it to work.
I'm starting to not like it. :-) The problem is:
template<class X> void f(S_ptr<X> px);
where f doesn't support arrays. A reasonably common occurence. S_array<> doesn't match, but S_ptr<T[]> does. The author of f would need to learn about enable_if to prevent array pointers from being passed to f. This is not good, although the exact degree of not-goodness is somewhat debatable.
I understand your hesitation. But I'm not yet seeing a concrete case to support it. There are two situations to analyze here: 1. Client writes: template<class X> void f(S_ptr<X> px); and intends to catch only pointers to single objects, and does not want to deal with pointers to arrays. 2. Client writes: template<class X> void f(S_ptr<X> px); and intends to catch pointers to both single objects and array objects. In case 1, learning about enable_if is not necessarily a bad thing. Indeed, a significant portion of the standard headers would be much better behaved today if we (as a community) had better understood the value of restricted templates, how to implement them, and the dangers of templates with unrestricted syntax, but restricted semantics. For example: template <class InputIterator, class Distance> void advance(InputIterator& i, Distance n); That is what we meant. But to the compiler we wrote: template <class T, class U> void advance(T& x, U y); The difference is really startling. Learning about enable_if is a feature, not a bug! :-) Now if the author intends case 1, enable_if is only one route to take. Another very easy thing to say is: template<class X> void f(S_ptr<X> px) { static_assert(!is_array<X>::value, "X must not be an array type"); ... } Reference: http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1424.htm http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1381.htm This boils down to: Is S_ptr<X[]> going to become a familiar enough idiom that the average C++ programmer is going to be educated enough to deal with it? That's a real question. Imho we either fully embrace it or fully abandon it. In case 2, where the programmer wants to collect smart pointers to single objects and arrays, then the syntax is clearly a benefit (as Bronek pointed out earlier in this thread). There isn't a whole lot that a client could do with both S_ptr<X> and S_ptr<X[]>, but that cuts both ways: If the attempted syntax is common, it will likely work: template<class X> void f(S_ptr<X> px) { px.reset(); } If the attempted syntax is not common, then it will likely not work: template<class X> void f(S_ptr<X> px) { *px; } Are there use cases where a programmer could naively assume 1, but end up with 2? Are there use cases where you really need 2? Looking for good use cases.... I've been exploring copy_ptr and clone_ptr lately. There is a connection that may be relevant. Consider vector<S_ptr<T> >. When you copy that container, what should be the semantics? vector<shared_ptr<T> > : copy shares ownership with source vector<move_ptr<T> > : copy not possible, but can move (transfer) ownership from source to target vector<copy_ptr<T> > : copy uses new T(*t) to "deep copy" each element. vector<clone_ptr<T> > : copy uses t->clone() to "deep copy" each element. In the first two cases, if T turns out to be an array type, there isn't that much to be concerned about. But in the latter two cases if T is an array type, you really need to know how many elements are in the array to pull off a correct copy. So... vector<copy_ptr<int[3]> > : copy_ptr's copy ctor could know how many elements are in the array and do the right thing (and similarly for clone_ptr<T[N]>). copy_ptr<T[N]> would only be convertible to copy_ptr<T[M]> if N == M. copy_ptr<T[]> would not be copyable at all because it doesn't know how many elements to copy. I'm just kind of rambling in public (which is always a foolish thing to do). I haven't prototyped any of this yet. Thoughts? -Howard

On 1/27/04 7:39 PM, "Howard Hinnant" <hinnant@twcny.rr.com> wrote:
On Jan 27, 2004, at 11:06 AM, Peter Dimov wrote:
Need to be? No. But I still like it. <shrug> I was convinced because that's how a newbie expected it to work.
I'm starting to not like it. :-) The problem is:
template<class X> void f(S_ptr<X> px);
where f doesn't support arrays. A reasonably common occurence. S_array<> doesn't match, but S_ptr<T[]> does. The author of f would need to learn about enable_if to prevent array pointers from being passed to f. This is not good, although the exact degree of not-goodness is somewhat debatable.
I understand your hesitation. But I'm not yet seeing a concrete case to support it.
There are two situations to analyze here:
1. Client writes:
template<class X> void f(S_ptr<X> px);
and intends to catch only pointers to single objects, and does not want to deal with pointers to arrays.
2. Client writes:
template<class X> void f(S_ptr<X> px);
and intends to catch pointers to both single objects and array objects.
In case 1, learning about enable_if is not necessarily a bad thing. Indeed, a significant portion of the standard headers would be much better behaved today if we (as a community) had better understood the value of restricted templates, how to implement them, and the dangers of templates with unrestricted syntax, but restricted semantics. For example: [TRUNCATE]
If the solution to the "S_ptr<X[]>" idiom is to study up some more on other C++ idioms, then I think that we have a Big Red Flag that something is wrong with the new idiom. There are two things I read about in GUI programming: 1. Don't make a big deal of differentiating things that are similar. 2. Don't hide differences that matter. The C++ committee screwed up [2] with std::vector<bool>. I don't want another screw-up introduced, especially if it's more insidious and deliberate. (i.e. We should let this idiom die.) -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com
participants (6)
-
Daniel Wallin
-
Daryle Walker
-
David Abrahams
-
Howard Hinnant
-
Jonathan Turkanis
-
Peter Dimov