From: Thiago A. on

> I fail to see the very advantage of a new key word
> (with all it's implications - can I/need I specialize
> templates for it?) compared to the current library
> solution. Or shorter: What is the advantage of
>
> unique* T
>
> over
>
> std::unique_ptr<T>


* Better syntax, without templates and includes

* Better error messages

* Fast code?

* Array compatibility

void F(const Resource* p, int n) {... }
std::vector<std::unique_ptr<const Resource>> v;

//error (maybe it works with reinterpret_cast?)
F(&v[0], v.size());


I started to think about this subject because of syntax questions, and
because I think pointer ownership is a basic concept of the language.

We know that the language evolutes first through libraries and this
can make the language less expressive and difficult to use. Sometimes
the language changes to suport better something used as a library.
The unique_ptr itself started with auto_ptr and now using the move
semantics.
We have the null_ptr and bool which started as NULL and BOOL.

First I imagined a direct syntax conversion between unique_ptr<T> and
unique T *, however with good error messages.
This raised the "deleter" question. "Where the deleter is
specified?"
Then I tried a "flat" version without the deleter and the operator
delete with an extra optional argument "deleter".

Maybe a template specialization could be beneficed with a type
modifier, maybe not; I confess I don�t have a real template problem/
motivation.

I haven�t used the unique_ptr so much, but if I had to choose a smart
pointer for RAII I would choose the unique_ptr.
I still not sure if I will change the normal pointer style for unique
pointers.



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Daniel Krügler on
On 27 Jul., 07:31, Dragan Milenkovic <dra...(a)plusplus.rs> wrote:
> On 07/26/2010 07:45 PM, Daniel Kr�gler wrote:
>
> > On 25 Jul., 16:27, Dragan Milenkovic<dra...(a)plusplus.rs> wrote:
>
> > [..]
>
> >> I didn't give thought or searched for existing discussions
> >> on this topic, but there is another, much more important item
> >> that you forgot... The support for covariant return types...
>
> > Since you are already changing the subject: It might be
> > helpful, if you would be more specific in this point as
> > well, because covariant return types are supported in
> > C++. I assume you have something similar in mind
> > as discussed in the older thread "Treating Foo<T>* as
> > Foo<const T>*",[1] extended to "Treating Foo<Derived>* as
> > Foo<Base>*" or to "Treating Foo<Derived> as
> > Foo<Base>" but that is just guessing.
>
> I assumed that OP meant to incorporate shared_ptr into
> the language as opposed to being a library. He refers
> to it as a modifier, although this would not be it's
> nature. At least this is how I understood it...

I think you understand the OP pretty well, but I did
not understand your remark well ;-) - sorry for that!

> I don't have any proposal and can live with the current
> state of things. I was simply stating one additional
> advantage so he can give more thought to his proposal
> (I hope that came out right).

After rereading your message I agree that you were pretty
clear.

> Disclaimer: I will now be plain silly:
>
> std::shared_ptr<Foo> foo = std::make_shared<Foo>();
>
> Foo $ foo = std::make_shared<Foo>();
>
> ... end of silliness.

I see, but I wonder which would be the compiler rules
in regard to "sharing"? It seems that uniqueness
constraints are easier to check than sharing constraints.

> And about treating Foo<Derived> as Foo<Base>; it can
> somewhat be solved by a conversion operator, right?

Typical implementations do this by providing a converting
constructor, yes. This is the way unique_ptr and shared_ptr
are specified. This does not allow for binding a *pointer*
or reference of type unique_ptr<Derived> to a corresponding
object of type unique_ptr<Base>, though.
While it is - with some efforts - possible to realize that
in regard to cv qualifications (as shown in the referenced
thread), this is not so easy to realize in a completely
general way in regard to inheritance relations (but I haven't
tried it yet).

> It's just that I sometimes wish that some conversions
> were transitive (can be chained automagically)... :-)
> and I don't necessarily speak about templates.

I understand this, but I'm not sure that the resulting increase
of the complexity of the type system is worth the effort.
IMO it is similar or even more drastic than allowing to
overload the operator., see

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1671.pdf

Alternative approaches are to allow for user-providing
conversion operators, as shown in

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2200.pdf

Greetings from Bremen,

Daniel Kr�gler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Thiago A. on
>
> > - Better error message generated by compiler
>
> Can you show a plausible compiling error with std::unique_ptr that
> would be improved with your suggestion?

Any error will expand the template and give us at least 10 lines of
error message.

struct Myclass { unique_ptr<Resource> p; };
Myclass a;
Myclass b;
a = b;

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Andy Venikov on
Thiago A. wrote:
>> I fail to see the very advantage of a new key word
>> (with all it's implications - can I/need I specialize
>> templates for it?) compared to the current library
>> solution. Or shorter: What is the advantage of
>>
>> unique* T
>>
>> over
>>
>> std::unique_ptr<T>
> * Better syntax, without templates and includes

I actually find unique_ptr<int> a pretty nice way of describing what you want. I don't think that the syntax argument is a strong argument.


> * Better error messages
This is in my view the best and only argument for unique type modifier.


> * Fast code?
I think that modern compilers will compile all operations on unique_ptr<T> as though it was T*, so the run-time speed will be extremely efficient.

> * Array compatibility
> void F(const Resource* p, int n) {... }
> std::vector<std::unique_ptr<const Resource>> v;
> //error (maybe it works with reinterpret_cast?)
> F(&v[0], v.size());

Well, you just broke the uniqueness of the pointers by trying to pass them to F while at the same time keeping them in the vector. Not unique anymore.


<snip>


Andy.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Dragan Milenkovic on
On 07/27/2010 04:45 PM, Daniel Kr�gler wrote:
[snip]
>> And about treating Foo<Derived> as Foo<Base>; it can
>> somewhat be solved by a conversion operator, right?
>
> Typical implementations do this by providing a converting
> constructor, yes. This is the way unique_ptr and shared_ptr
> are specified. This does not allow for binding a *pointer*
> or reference of type unique_ptr<Derived> to a corresponding
> object of type unique_ptr<Base>, though.

But this is not possible even with simple pointers. They too
need to be converted from Derived * to Base *. I cannot
even think of many differences between a smart pointer
and a pointer (except for covariant returns, and something
related to template resolution)... I guess this tells that
smart pointers have been done right. :-)

[snip]
>
>> It's just that I sometimes wish that some conversions
>> were transitive (can be chained automagically)... :-)
>> and I don't necessarily speak about templates.
>
> I understand this, but I'm not sure that the resulting increase
> of the complexity of the type system is worth the effort.
> IMO it is similar or even more drastic than allowing to
> overload the operator., see
[snip]

One of my free-time designs evolved into something like this:

class Foo_impl {blabla};
class Bar_impl : public Foo_impl {blabla};

And these classes are then passed around and composed into
other classes through shared_ptrs.

On the other side, the public interface contains concrete
classes Foo and Bar which wrap shared pointers and provide
public functions.

I found this design very nice because it greatly simplifies
the public interface, separates the implementation (which
can and was refactored a few times without changing
the public interface), allows for operators such as &&, ||.
The first impression is that it increases complexity,
but it actually made my life easier.

Of course, I wanted to convert Bar into Foo. This works nice
until there comes Joe. (Joe_impl inherits Bar_impl).

struct Bar {
operator Foo () const;
};

struct Joe {
operator Bar () const;
operator Foo () const; // Joe no like Foo...
};

This is just a sample. The main reason for me wanting some
kind of cascade (disclaimer: I have not given thought about
what and how to do it), is that I renamed and changed
the design all the time, trying how the new one would behave.
Much time was lost on things that I would call secondary,
such as converting Joe to Foo... That's it.

Actually, as this was my last-year work, I just checked...
there are no conversion operators left. I guess I removed them
all until the design becomes stable; or perhaps changed
the design to not require them. But I'm sure I experimented
with this stuff. I even had Foo_const, Bar_const variants
which added to the complexity of casts. Also I tried
making templates and using enable_if, etc...
Now I will stop with the boring stuff... thanks for reading.

--
Dragan


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]