-
Notifications
You must be signed in to change notification settings - Fork 112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
out_ptr/inout_ptr for all smart pointer types #56
Comments
The library in principle supports C++03, but it's fine for independent parts of it to require C++11. I'm not fond of undefined behavior; what do you think about adding a separate |
There is no need for The other UB would only apply to |
Would you please explain why we need an assignment operator in |
Most types that have a move constructor have a move assignment operator. While not part of its usage, I was told it was very strange and irregular to have the move constructor without the move assignment operator. Guaranteed copy/move elision means we can technically get away without having one, but for C++11, we're going to need it. I don't mind having the |
I'm actually not quite sure why we need a move constructor either. :-) Or was that what you had in mind with
|
Another question, why does |
OK, let's look at the static casts. The second one, in the destructor, enables
This is not safe, because The first cast, in the constructor, enables the opposite case:
This is not safe because Note that this second example is safe and would not require a cast if we use The question, to my mind, is do we want the above to compile? Are the use cases (to the extent there are any) outweighed by the possibility of errors, such as passing the wrong |
Post-C++11, Guaranteed Copy/Move Elision was voted into the standard as essentially a strengthening of Return Value Optimization. That means you can return a value that is neither copyable or movable from a function, so long as you can guarantee that RVO will be performed as defined by the language. In C++11 and earlier, even if RVO would kick in, you are not allowed to return an object that is neither copyable or movable. Even if the compiler never actually invokes either by as-if rules, it was still required to be there. Since C++11 is the target for Boost.Smartptr, we need the move constructor. The move assignment operator just came along for the ride so that the type itself is not "Too Weird". I also was doing tests and found that sometimes a move operation was being called that subtly did the wrong thing, so I needed to define one to be safe.
That's a mistake! Thanks for catching it in the wording: it came from an older implementation I was working on that didn't need the
Right, but there are functions in COM (
Again, the user has opted into this behavior by adding the template parameter. Default usage is just |
Yes. Your proposal can get in C++23 at the earliest though, and elision is guaranteed there. So the specification doesn't need to have a move constructor. And if there's no move constructor, no need to have move assignment either. In the C++11 implementation we'll have a move constructor out of necessity, but we don't need the move assignment as nothing requires it. Regrading How important is this optimization for you? Would it be acceptable if the Boost implementation doesn't have it? |
At dinner, JeanHeyd mentioned he needed access to a @ThePhD What is the plan for the Also, so that I haven't misunderstood, no such hooks are needed in a |
I originally had no move constructor or assignment constructor specified. The person who helped me write the wording made it very explicit that I need to define whether the type is movable, copyable, etc. If not, then I should delete all of the constructors / assignment operators, but I haven't gotten that design decision looked at by anyone just yet. I also noticed in tests on some compilers that the Move Constructor / Move Assignment was being invoked anyways (and they just did memberwise relocation, which is wrong for these types). After that I decided it was better to define it and not have any dangling questions about how it might work (and RVO can still not use it).
I think I could probably just change the wording to say it's set to an unspecified value. That would allow for the
In either case, this is part of the design: once it's here, boost::move can decided how it will react to specializing the template (either not at all (no performance gain) or by adding it (performance gain)). I think the only thing we'll need to define is a macro, |
As another side note: the optimization for getting out the value is only really applied to The optimization for The most important one is for |
In the case of |
Yes. If it reseats the pointer then all the implementation has to do is |
That's because the optimizer doesn't know whether the C-like function doesn't access the "external" smart pointer. Truth be told, I don't like this optimization in any of the cases, and I'd rather not have it. |
Incidentally, this means that the optimization is non-conforming given the current wording. You can detect if the constructor of |
I think if I shift the wording to have |
You also need something like "If (The function can |
For the Boost implementation, I agree. It might be a concern for standardization and why the paper does go to considerable effort to cover performance, because some people believe this is only viable if there is no added cost, but that does not have to be the case for us. @ThePhD, does that sound reasonable? This would mean that in the Boost documentation we would not be advertising performance of any kind, like the paper does. This feature would only be about convenience and safety (which to me is the main motivation for using it anyway). i.e. We could not say that using |
If you mean something like |
OK, after a few more experiments I'm coming around to the idea that the optimization may be worth it: https://gcc.godbolt.org/z/rxt-nE |
Meanwhile, for That said, I suspect the interested users are after this mainly for |
For SharedThe code may not look great for shared pointer but the actual speed is fine (for this one compiler (VC++), on this one machine (old Intel i7)). The benchmarks benchmark 2 types but that was purely laziness on my part, the underlying implementation for clever / simple is all the same (I can't think of clever ways to avoid extra work for For
|
The code not looking great might be a deal breaker for some people (those that do not want to incur the extra bloat). But the actual speed is not fine when I wrote benchmarks for the above. I observed With I'll try MSVC as you suggest to compare these functions there too, and get the results into some presentable state to publish. |
I updated and ran some more benchmarks to cover the cases if f1, f2 and their usages in g2 and g3. I haven't actually fixed my fake C API to return an error, so I can't do the equivalent of Creating/Returning a new shared_ptrThe benchmarks covered a few cases. Peculiarly, in almost all cases where some call to I don't know what magic MSVC is doing to make these numbers. The code is here. I didn't look at the codegen yet. Resetting a pre-existing shared_ptrThis has expected characteristics: we have to reset a pre-existing pointer. Both solutions clock in with the same standard deviation and the same average, +-.5 nanoseconds. Also, Happy Thanksgiving for anyone based in the US! 🦃 |
Dear Boost.SmartPtr authors:
(This issue is a continuation of the discussion from Boost.Move.)
My name is JeanHeyd and I am looking to make my std::out_ptr / std::inout_ptr type that I am proposing to the standard more widely and publicly available. I was given the advice to put it in Boost in some fashion, and I realized that rather than making a new library contribution it would be better off if this was put in one of the 2 smart pointer-containing libraries, Boost.Move or Boost.SmartPtr.
The author of Boost.Move has stated that it seems like a better match for Boost.SmartPtr, and I agree: therefore, I am proposing to add 2 new templated functions and 2 new templated classes:
boost:out_ptr( ... );
andboost::inout_ptr( ... );
alongsideboost::out_ptr_t<Smart, Pointer, Args...>
andboost::inout_ptr_t<Smart, Pointer, Args...>
.I wanted to know if this was acceptable to the library maintainers here, and if so I would begin to move the current implementation into Boost.
If it is not acceptable, I understand.
If it is acceptable, I would like to know what version of C++ Boost.Smartptr targets and any other caveats I should be careful of when crafting my first pull request. I can do a C++11 implementation without the need for workarounds, but C++03 will require some finesse.
Please do let me know what you think! I eagerly await your response.
Sincerely,
JeanHeyd
The text was updated successfully, but these errors were encountered: