On 18 October 2016 at 16:08, <mihailn...@gmail.com> wrote:
> In any case, for a smart pointer, reset and release are lifetime management
> interfaces.
>
> observer_ptr changes this.
But yet its users are unlikely to find this a problem, because some of
them don't consider
reset and release to be lifetime management interfaces.
> Also note, owner<> and not_null<> do not have these also!
Well, of course not, because they are raw pointers.
On Tuesday, October 18, 2016 at 4:17:29 PM UTC+3, Ville Voutilainen wrote:On 18 October 2016 at 16:08, <mihailn...@gmail.com> wrote:
> In any case, for a smart pointer, reset and release are lifetime management
> interfaces.
>
> observer_ptr changes this.
But yet its users are unlikely to find this a problem, because some of
them don't consider
reset and release to be lifetime management interfaces.reset and release is lifetime interface in the context of a smart pointer - if you touch these, the lifetime of the object will change.That's a fact, not a point a view.
unique_ptr's release appears to be an evolution of auto_ptr's. Which also "detached"
The first 4 "detach" - ie break the association, without changing the underlying object lifetime/state/refcount
The last 2 actually release the memory.On Tue, Oct 18, 2016 at 9:44 AM, <mihailn...@gmail.com> wrote:
On Tuesday, October 18, 2016 at 4:17:29 PM UTC+3, Ville Voutilainen wrote:On 18 October 2016 at 16:08, <mihailn...@gmail.com> wrote:
> In any case, for a smart pointer, reset and release are lifetime management
> interfaces.
>
> observer_ptr changes this.
But yet its users are unlikely to find this a problem, because some of
them don't consider
reset and release to be lifetime management interfaces.reset and release is lifetime interface in the context of a smart pointer - if you touch these, the lifetime of the object will change.That's a fact, not a point a view.release() doesn't change the object's lifetime for unique_ptr - it hands the pointer back to you, still alive.
Having similar functions use the same names as functions of the slighlty smarter pointers, might help replacing those with an observer_pointer. Changing "release" into "stop_observing" (or something) doesn't appeal to me.
If we look at a similar problem in merging "optional", "variant", and "any" into the draft standard, we ended up with two of them having a "bool has_value()" function, while the third got a "bool valueless_by_exception()".
Not only do they have different names, but also different true/false return value for the same(?) condition - does it store anything.
Bo Persson
> observer changes this, overloads what reset means, all that for no good
> enough reason (by a long shot).
Well, reset() means what it always meant, it resets the handle to have
some other pointer or none.
I was surprised to see http://en.cppreference.com/w/cpp/experimental/observer_ptrI though, it was settled, raw pointers will be serving as non-owning pointers? (and use references, as well not_null<> and owner<> to cover corner cases and legacy)
..
I don't know how many times I need to point out that reset() on a
unique_ptr might have no
effect on the object lifetime, depending on the deleter.
std::unique_ptr is a smart pointer that retains sole ownership of an object through a pointer and destroys that object when the unique_ptr goes out of scope. No two unique_ptr instances can manage the same object.The object is destroyed and its memory deallocated when either of the following happens:
the managing unique_ptr object is destroyed
the managing unique_ptr object is assigned another pointer via operator= or reset().The object is destroyed using a potentially user-supplied deleter by calling Deleter(ptr). The deleter calls the destructor of the object and dispenses the memory.
...
All else is subject to the semantics of any possible custom deleter
provided, and none of that nonsense
on cppreference applies to such custom deleters. The standard doesn't
make such incorrect claims about
how unique_ptr works.
On Tuesday, October 18, 2016 at 4:17:29 PM UTC+3, Ville Voutilainen wrote:On 18 October 2016 at 16:08, <mihailn...@gmail.com> wrote:
> In any case, for a smart pointer, reset and release are lifetime management
> interfaces.
>
> observer_ptr changes this.
But yet its users are unlikely to find this a problem, because some of
them don't consider
reset and release to be lifetime management interfaces.reset and release is lifetime interface in the context of a smart pointer - if you touch these, the lifetime of the object will change.That's a fact, not a point a view.
observer_ptr pretends to be smart with risk of being harmful and/or confusing.
On Tuesday, October 18, 2016 at 9:44:40 AM UTC-4, mihailn...@gmail.com wrote:
...
No, it is a point of view.
To hold onto a smart pointer object means that you expect the object pointed to by the smart pointer to continue to exist, pursuant to the smart pointer's contract. A `weak_ptr` does not ensure the lifetime of the pointed-to object. What it does ensure is that, if that lifetime has ended, you'll know about it. You may get a NULL pointer, but you'll never get an invalid one.
When you `reset` a smart pointer, you are saying that you no longer expect that object to exist. Whether or not it is actually destoryed is smart-pointer specific. `shared_ptr::reset` doesn't guarantee the object will be destroyed. `weak_ptr::reset` doesn't destroy anything at all.
By calling `reset`, you are making a contract with the smart pointer. From that point forward, you will not do anything to access the object referenced by that smart pointer, nor any object who's lifetime depends on it, unless you have a guarantee from some other object. That is, as far as this particular smart pointer is concerned, it is not going to ensure anything.
`release` isn't even a function that most smart pointers have.observer_ptr pretends to be smart with risk of being harmful and/or confusing.
To whom is it harmful or confusing? Are you actually trying to claim that someone is going to assume that a smart pointer with the word "observer" in it is going to manage memory?
Anyone who does that deserves what they get.
The point of `observer_ptr` is to represent when a function is being given a pointer it does not have ownership of.
On Tuesday, October 18, 2016 at 11:09:48 PM UTC+3, Nicol Bolas wrote:On Tuesday, October 18, 2016 at 9:44:40 AM UTC-4, mihailn...@gmail.com wrote:...
No, it is a point of view.
To hold onto a smart pointer object means that you expect the object pointed to by the smart pointer to continue to exist, pursuant to the smart pointer's contract. A `weak_ptr` does not ensure the lifetime of the pointed-to object. What it does ensure is that, if that lifetime has ended, you'll know about it. You may get a NULL pointer, but you'll never get an invalid one.
When you `reset` a smart pointer, you are saying that you no longer expect that object to exist. Whether or not it is actually destoryed is smart-pointer specific. `shared_ptr::reset` doesn't guarantee the object will be destroyed. `weak_ptr::reset` doesn't destroy anything at all.reset on a waek_ptr does not take a pointer! It does not overload the meaning of reset!
By calling `reset`, you are making a contract with the smart pointer. From that point forward, you will not do anything to access the object referenced by that smart pointer, nor any object who's lifetime depends on it, unless you have a guarantee from some other object. That is, as far as this particular smart pointer is concerned, it is not going to ensure anything.reset purpose is to re-set the smart pointer to a new value.
auto *ptr = smart_ptr_from_somewhere.get();
smart_ptr_from_somewhere.reset();
ptr->stuff();
Same with release - touching it, means you are touch the deleter call, when and if it runs.
`release` isn't even a function that most smart pointers have.observer_ptr pretends to be smart with risk of being harmful and/or confusing.
To whom is it harmful or confusing? Are you actually trying to claim that someone is going to assume that a smart pointer with the word "observer" in it is going to manage memory?O, yes I do. The moment a lib typedefs these, you are left to wonder what's up with all those reset-s and release-s.
You look a function and an observer is used.Then you switch to another function, you see exactly the same code, but this time it is not an observer and you forgot to look up the type.
You spend 10 min consuming the code in the wrong way, thinking it does one thing, but it does something different.
This has the exact same problem as if one overloads a smart pointer operator= on the managed type.
Anyone who does that deserves what they get.
The point of `observer_ptr` is to represent when a function is being given a pointer it does not have ownership of.As commented, raw pointers are left for that use, and that use only.
By calling `reset`, you are making a contract with the smart pointer. From that point forward, you will not do anything to access the object referenced by that smart pointer, nor any object who's lifetime depends on it, unless you have a guarantee from some other object. That is, as far as this particular smart pointer is concerned, it is not going to ensure anything.reset purpose is to re-set the smart pointer to a new value.reset always, to this point, controls the deleter call - one way or another (right away call, pointer dtor call, use_count etc, etc does not matter).This is what a smart pointer ensures, this is what is designed for.
Same with release - touching it, means you are touch the deleter call, when and if it runs.So, right now and for many, many years, these are lifetime management APIs.
`release` isn't even a function that most smart pointers have.observer_ptr pretends to be smart with risk of being harmful and/or confusing.
To whom is it harmful or confusing? Are you actually trying to claim that someone is going to assume that a smart pointer with the word "observer" in it is going to manage memory?O, yes I do. The moment a lib typedefs these, you are left to wonder what's up with all those reset-s and release-s.And what about auto? The explicit type is less and less visible in modern code.Even if not typedefed, even if you learn the types, you will have to constantly remind yourself, "is this is observer or is it not".You look a function and an observer is used.Then you switch to another function, you see exactly the same code, but this time it is not an observer and you forgot to look up the type.You spend 10 min consuming the code in the wrong way, thinking it does one thing, but it does something different.This has the exact same problem as if one overloads a smart pointer operator= on the managed type.Two completely different actions (pointer copy and deleter management) are expressed by visually the same code.Sure, the type is different, but in this case this is not enough - you better use different language for different things.reset is that different language.
Anyone who does that deserves what they get.
The point of `observer_ptr` is to represent when a function is being given a pointer it does not have ownership of.As commented, raw pointers are left for that use, and that use only. No confusion if owner<> is used instead. No overloading of operations. No new concepts.And BTW owner<> is better, because it signals the unordinary (in modern code) case, it is labeled, because it is special.Raw pointer is not labeled, he is not special.
auto p = foo();
if(cond(p))
p.reset(hello.getBar());
Ok,I hope we all agree reset(T*) and release() have new meaning in the context of a observer_ptr. Ok?For you, it is not a problem - the class is free to add whatever meaning it wants to.I simply argue, it can well be a problem and potentially adding a confusion.
auto p = foo();
if(cond(p))
p.reset(hello.getBar());All I am saying, this code above, for current smart pointers, meant - p now has the bar object.With observer_ptr into the picture, it might also mean - p now points to a bar.
There is some overloading, which I personally find unfortunate and not well justified.
That's all.-Now lets look at release, which has also a different problem.std::unique_ptr::release
std::shared_lock::releasestd::unique_lock::releasestd::pmr::monotonic_buffer_resource::releasestd::pmr::unsynchronized_pool_resource::releaseWhat is common b/w these all?They all give up a resource, which affects other objects in the system.In general, right now, when you see release() in code, something quite important, worth noting is happening.Something possibly requiring some other actions to take care of.None of these are trivial operation.observer_ptr makes it trivial.It makes it only about itself, it does not affect other objects and state.Ok, for you it might not be a problem.I only argue, it might well be - release() statement in code loses from its importance.The important uses of release() will be accompanied of trivial uses of it.Not a good thing.
在 2016年10月19日星期三 UTC+8下午4:30:37,mihailn...@gmail.com写道:Ok,I hope we all agree reset(T*) and release() have new meaning in the context of a observer_ptr. Ok?For you, it is not a problem - the class is free to add whatever meaning it wants to.I simply argue, it can well be a problem and potentially adding a confusion.
auto p = foo();
if(cond(p))
p.reset(hello.getBar());All I am saying, this code above, for current smart pointers, meant - p now has the bar object.With observer_ptr into the picture, it might also mean - p now points to a bar.
For current smart pointers in the standard, it is also true. The assumption is just further weaken (correctly).
...
I am aware of the existence of not_null in the GSL, as well as the proposed propagate_const wrapper. However, I'm not sure how I feel about littering my code with these beauties:
propagate_const<not_null<observer_ptr<T*>>> obs = make_observer(&obj);
What's more, you have to ask, why are we starting with a type which is ill-fitting to model a const-correct, not-null observer type (T*) and then layering it with various wrappers designed to mould it into something which fits the bill? Wouldn't it be better to design separate wrapper types which just do the job?
observer<T> obs = obj;
optional_observer<T> opt_obs = obj;
propagate_const<observer<T>> obs = obj;
- It is cumbersome to use: any pointer can be "observed" safely, so why do I have to use make_observer or reset to change what I'm observing? This seems to be due to observer_ptr being based on unique_ptr (hence the inappropriate release function) which understandably wants to prevent accidental assignment of arbitrary raw pointers, since it takes ownership of whatever it holds. The API is appropriate for an owning pointer, not an observing pointer (p.s. the presence of a reset function would be a bike shed issue if direct assignment were possible).
- It has a null state: this is sometimes desirable, but references are frequently used instead of pointers to "observe" something while precluding the possibility of not observing anything. Of course, pointers can be used, but care must be taken not to dereference a null pointer; it is better (IMO) to have compile-time assurance that your reference type cannot be null. Where the the null-less counterpart to observer_ptr?
- It is not const-correct: pointers circumvent the "const-correct" nature of the C++ type system; a const pointer is not implicitly a pointer to const. This should be the default behaviour of any "observer" type. In fact, this should be the behaviour of any "owner" type as well; I feel as though unique_ptr and shared_ptr should have really been called unique_owner and shared_owner, and should have exhibited const-correct behaviour. That said, I can see value in the flexibility of pointer-like owning types, so perhaps we are in need of both sets of types (that is, if propagate_const cannot solve the issue satisfactorily; I'm not yet sure it can).
On Wednesday, October 19, 2016 at 8:05:07 PM UTC+3, joseph....@gmail.com wrote:...
- It is cumbersome to use: any pointer can be "observed" safely, so why do I have to use make_observer or reset to change what I'm observing? This seems to be due to observer_ptr being based on unique_ptr (hence the inappropriate release function) which understandably wants to prevent accidental assignment of arbitrary raw pointers, since it takes ownership of whatever it holds. The API is appropriate for an owning pointer, not an observing pointer (p.s. the presence of a reset function would be a bike shed issue if direct assignment were possible).
- It has a null state: this is sometimes desirable, but references are frequently used instead of pointers to "observe" something while precluding the possibility of not observing anything. Of course, pointers can be used, but care must be taken not to dereference a null pointer; it is better (IMO) to have compile-time assurance that your reference type cannot be null. Where the the null-less counterpart to observer_ptr?
- It is not const-correct: pointers circumvent the "const-correct" nature of the C++ type system; a const pointer is not implicitly a pointer to const. This should be the default behaviour of any "observer" type. In fact, this should be the behaviour of any "owner" type as well; I feel as though unique_ptr and shared_ptr should have really been called unique_owner and shared_owner, and should have exhibited const-correct behaviour. That said, I can see value in the flexibility of pointer-like owning types, so perhaps we are in need of both sets of types (that is, if propagate_const cannot solve the issue satisfactorily; I'm not yet sure it can).
The irony is, raw pointer + not_null OR (preferably) reference covers all 3.
- It is trivial to use, nothing new to learn, age-old and simple proven concept, fast as hell, terse syntax
- null state acts as an optional pointer. Else - references or not_null. And BTW not_null<> is not for sanitizing legacy code. owner<> is, but not_null is legit decoration even for modern code because there is no new alternative.
not_null<T*> obs = &obj;
not_null<T> obs = obj;
observer<T> obs = obj;
optional_observer<T> opt_obs = obj;
- it is const correct - const S* will not let you call non-const functions.
Yes, it is a problem, it does much more.But the idea is to cover all other cases with some other pointer type and leave the good old pointer only for certain scenarios.I do understand, people will disagree - they don't want raws in upper level, in day to day object management, I get that.
My intentions are not to change your mind - we, as well as everyone else, are perfectly aware of the pros and cons of both approaches - raw vs new ptr.
We also agree, any "operator." (in quotes, not necessarily overloading it) will dramatically change any possible implementation of such a wrapper pointer type.
I also agree with you propagate_const should be integral part of such a wrapper pointer type, not a cumbersome opt-in.
As a result, I (still) strongly believe observer_ptr should not go into the standard in its current form.It will be half-assessed, and will rise as many issues/questions as it solves and will be become the auto_ptr version of a much better view type.
On Wednesday, October 19, 2016 at 1:29:04 PM UTC+3, FrankHB1989 wrote:
在 2016年10月19日星期三 UTC+8下午5:58:55,mihailn...@gmail.com写道:
On Wednesday, October 19, 2016 at 12:38:30 PM UTC+3, FrankHB1989 wrote:
在 2016年10月19日星期三 UTC+8下午4:30:37,mihailn...@gmail.com写道:Ok,I hope we all agree reset(T*) and release() have new meaning in the context of a observer_ptr. Ok?For you, it is not a problem - the class is free to add whatever meaning it wants to.I simply argue, it can well be a problem and potentially adding a confusion.
auto p = foo();
if(cond(p))
p.reset(hello.getBar());All I am saying, this code above, for current smart pointers, meant - p now has the bar object.With observer_ptr into the picture, it might also mean - p now points to a bar.For current smart pointers in the standard, it is also true. The assumption is just further weaken (correctly).
...Is it, really? For both (all?) smart pointers today, the meaning is the same - p is now master of bar. The only difference is, is this ownership shared with other p clones or not.Where in the observer case, it is something quite different.Again, it might well not be a problem, but I don't believe it is a difference to be taken lightly.No. A smart pointer is not necessarily owning, even if all instances in the current standard are owning. See also https://en.wikipedia.org/wiki/Smart_pointer, esp. external links.Of course, but the case in point is all the code written against the current notions, from both std and other implementations like Qt, and the effect observer will have.
Something like observer_ptr should exist. Use of raw pointers is simply too overloaded. Even if you buy the argument that, in modern C++, raw pointers have a single accepted use as non-owning references (and I don't**), something like observer_ptr narrows the range of operations to what is sensible for such a reference type (e.g. no pointer arithmetic). However, I believe the design of observer_ptr is not well tailored to its purported purpose:
- It is cumbersome to use: any pointer can be "observed" safely, so why do I have to use make_observer or reset to change what I'm observing? This seems to be due to observer_ptr being based on unique_ptr (hence the inappropriate release function) which understandably wants to prevent accidental assignment of arbitrary raw pointers, since it takes ownership of whatever it holds. The API is appropriate for an owning pointer, not an observing pointer (p.s. the presence of a reset function would be a bike shed issue if direct assignment were possible).
- It has a null state: this is sometimes desirable, but references are frequently used instead of pointers to "observe" something while precluding the possibility of not observing anything. Of course, pointers can be used, but care must be taken not to dereference a null pointer; it is better (IMO) to have compile-time assurance that your reference type cannot be null. Where the the null-less counterpart to observer_ptr?
- It is not const-correct: pointers circumvent the "const-correct" nature of the C++ type system; a const pointer is not implicitly a pointer to const. This should be the default behaviour of any "observer" type. In fact, this should be the behaviour of any "owner" type as well; I feel as though unique_ptr and shared_ptr should have really been called unique_owner and shared_owner, and should have exhibited const-correct behaviour. That said, I can see value in the flexibility of pointer-like owning types, so perhaps we are in need of both sets of types (that is, if propagate_const cannot solve the issue satisfactorily; I'm not yet sure it can).
On Thursday, 20 October 2016 15:09:16 UTC+8, mihailn...@gmail.com wrote:My intentions are not to change your mind - we, as well as everyone else, are perfectly aware of the pros and cons of both approaches - raw vs new ptr.
I think it helps to have these things written down. Even if everyone else knows everything already, it helps me get my thoughts in order and realize where my reasoning is flawed.
We also agree, any "operator." (in quotes, not necessarily overloading it) will dramatically change any possible implementation of such a wrapper pointer type.
I don't agree with this. I think "operator dot overloading" will have limited to no application in this case. I believe it will have more of an application with types that act to modify select parts of an API while retaining the overall appearance of the underlying type like, for example, propagate_const.
I also agree with you propagate_const should be integral part of such a wrapper pointer type, not a cumbersome opt-in.
I'm in two minds about this. It may be better to keep const propagation separate.
On Thursday, October 20, 2016 at 11:45:10 AM UTC+3, joseph....@gmail.com wrote:On Thursday, 20 October 2016 15:09:16 UTC+8, mihailn...@gmail.com wrote:We also agree, any "operator." (in quotes, not necessarily overloading it) will dramatically change any possible implementation of such a wrapper pointer type.
I don't agree with this. I think "operator dot overloading" will have limited to no application in this case. I believe it will have more of an application with types that act to modify select parts of an API while retaining the overall appearance of the underlying type like, for example, propagate_const.Considering all proposals include an impl of a smart reference - it certainly will have significant impact.