| ||||
| Comment on GotW #89 Solution: Smart Pointers by Andrew Marshall (@planetmarshall)
What’s the advantage (if any) of weak_ptr over a non-owning raw pointer? Read More »Comment on GotW #6b Solution: Const-Correctness, Part 2 by Tomáš Šturm
You wrote on operator+: polygon may be a small type but it still contains std::vector as a member. And move-constructing that could make a significant difference in some use cases, couldn’t it? Read More »Comment on GotW #90: Factories by Ben Craig
1. Using a raw pointer doesn’t express the ownership semantics of the widget resource. Owning raw pointers should be avoided. 2. If widget is polymorphic, then unique_ptr<widget> is preferred. unique_ptr is preferable to a raw pointer or raw reference because of the automatic cleanup, but you still need some kind of pointer-like type for virtual functions to work. 3. If all callers were using unique_ptr already, then changing the return type from widget* to unique_ptr will not require source changes in client code. The unique_ptr constructor can take a returned unique_ptr just fine thanks to the move constructor. 4. If widget isn’t polymorphic, you should just return a widget value, and let move constructors do their thing. This lets you avoid the heap. Read More »Comment on GotW #6b Solution: Const-Correctness, Part 2 by Herb Sutter
@Fernando: You are correct, thanks. I’ve now added the copy and move operations; fortunately I could use = default for the latter. Read More »Comment on GotW #89 Solution: Smart Pointers by Marco
One thing we were discussing about a lot: are c++ shared_ptr threadsafe? Read More »Comment on GotW #89 Solution: Smart Pointers by Tom Kirby-Green
Hi Herb, is there any chance you could post somewhere your preferred pre ‘Milan’ (variadics) implementation for VS2012 Update 2 MSVC developers who want to use a pseudo blessed implementation of make_unique today? Read More »Comment on GotW #5 Solution: Overriding Virtual Functions by nosenseetal
or else it isn't, in which case the function has to be protected (private is not allowed because the derived destructor must be able to invoke the base destructor) and would naturally also be nonvirtual (when the derived destructor invokes the base destructor, it does so nonvirtually whether declared virtual or not). why it cant be public ? Doesnt placement new/delete require that(lets pretend that some crazy person wants to put polymorphic object in char[compile_time_max(sizeof (Base), sizeof (Der1),sizeof (Der2)...] Comment on GotW #6b Solution: Const-Correctness, Part 2 by mttpd
@Herb: Fair enough. Out of curiosity, are you concerns similar to those in the SO link (interaction with uniform initialization) or are there some other reasons? // Huh, perhaps brainstorming on this could make an interesting (JG?) question on its own… Read More »Comment on GotW #90: Factories by Ahti Legonkov
I agree with most what Ben Craig said, except with answer to 3. 3. What makes me so confident is the fact that in most places callers use `auto` instead of explicit types. Read More »Comment on GotW #90: Factories by Barry
I think Ben has it right, though I wonder if for (3) Herb meant that callers would be using: auto my_widget = load_widget(42); And that’s why it wouldn’t matter. Read More »Comment on GotW #89 Solution: Smart Pointers by nosenseetal
@herb (this is not ok) (up, sp set in other thread) @marco Comment on GotW #6b Solution: Const-Correctness, Part 2 by Fernando Pelliccioni
Hi Herb, hummmm… I think that “move-ctor = default” is not going to help. I don’t see anything abount std::atomic’s move-ctor in the Standard ( n3691 – [atomics.types.generic] ) If atomic copy-ctor is explicitly deleted, the, the move-ctor is deleted too ( implicitly ). I expected to find something like … atomic(atomic&&) = default; … in the Standard, but I didn’t find it. All this makes it very difficult to create classes with std::atomic or std::mutex as members. Comment on GotW #89 Solution: Smart Pointers by Anders Dalvander
make_shared can be wasteful if you have large objects and weak_ptr to these shared objects as the memory for the large object cannot be deallocated before the last weak_ptr has been destroyed. Sometimes it is better to use new instead of make_shared. Read More »Comment on GotW #89 Solution: Smart Pointers by paercebal
@Anders Dalvander A solution is to write your own “make_my_shared” insuring it will be expection safe and the new will be done outside the standard make_shared. This way, you keep the exception safety and follow the “don’t-write-naked-new” guideline, all the while separating the memory for the reference counters from the memory for your very-large-object. Read More »Comment on GotW #89 Solution: Smart Pointers by Kobi Cohen-Arazi
@herb Comment on GotW #90: Factories by BK
For a hierarchy of widget classes, the overridden load_widget function can return the specific widget type. The requirements for a return type by overridden functions is that they return covariant types (see n3242.pdf section 10.3 #7) Read More »Comment on GotW #89 Solution: Smart Pointers by Adrian
What happens if the class being instantiated with make_shared has class-specific new and delete operators? Will make_shared use that one (and thus still make a separate allocation for the control block)? Read More »Comment on GotW #90: Factories by jlehrer
for #4 you return a shared_ptr. This is because the shared_ptr holds a pointer to the destruction function which is determined at construction time. So, if the code creates a WidgetSubclass, then when the shared_ptr reference count goes to 0, the destructor function is called, and that function is ~WidgetSubclass, even if widget* is not polymorphic. Read More »Comment on GotW #89 Solution: Smart Pointers by andyprowl
I think the first two calls to sink() (in the answer to Q3) should not compile, since the constructor of unique_ptr that accepts a raw pointer is marked as explicit. Am I overlooking something? Read More »Comment on GotW #89 Solution: Smart Pointers by celeborn2bealive
Very interesting, I love your articles :) But I have a question about make_unique() and make_shared(): If i don’t say bullshit, when you allocate memory from a dynamic library, that memory must be freed in the code of the library. So for exemple if I have a function with the following signature in my library: std::unique_ptr<Widget> createButton(); I don’t understand how the compiler do things right to release the memory for the Widget in the library code (if it does…) since unique_ptr is a template class and I think its code will be instanciated in the client code. I know I can provide a custom deleter for the pointer (std::unique_ptr createButton();) to be sure, but in that case I cannot use make_unique() to create it (the same question holds for shared_ptr and it’s Deleter functor). Thank you for your answer and correct me if I’m wrong :) Read More »Comment on GotW #89 Solution: Smart Pointers by Michael Winterberg
nosenseetal: I think that you need to use the overloads of atomic_load and atomic_store that take shared_ptr for that to be acceptable. i.e. I’m pretty sure that individual instances of shared_ptr are not thread safe, only the reference counts that may be shared between multiple instances of a shared_ptr are. Read More »Comment on GotW #89 Solution: Smart Pointers by jlehrer
Responding to celeborn2bealive “when you allocate memory from a dynamic library, that memory must be freed in the code of the library.” says who? the C++ library says nothing about that. I know that with Visual C++, given certain compiler flags, that might be true. But it certainly isn’t true on any platform I use. If that is true on your platform, then you have some choices. My preferred method is to use an object factory which returns a shared_ptr. The shared_ptr, at construction time, encodes a pointer to the destruction function. The object factory then both constructs the new object AND encodes the destructor function, for free. When the shared_ptr’s counts go to 0, the caller, even if in a different library/toolkit/translation unit, still calls back into the same TU as the object factory to free the memory. Again, this happens automatically because the destructor function is populated in the same TU as the initial construction of the referenced object in the shared_ptr. Read More »Comment on GotW #89 Solution: Smart Pointers by David Svoboda
Great article but I have one question. I always assumed that you cannot make a vector of unique pointers of objects because the vector demands that an object always be copyable. And unique pointers are definitely not copyable. Perhaps the move semantics in C++ 11 Are what enables the creation of a vector of unique pointers. Read More »Comment on GotW #6b Solution: Const-Correctness, Part 2 by Leo
“Incidentally, notice that once we make rhs a reference-to-const parameter as noted above, we see another reason why get_point should be a const member function, returning either a const value or a reference to const.” Currently get_point returns neither. int i ... poly.get_point(i) = ... poly.get_point(i) += ... from compiling? But when assigning to a variable the top level const would be ignored and the variable could be used without constraints? Read More »Comment on GotW #6b Solution: Const-Correctness, Part 2 by Francisco Lopes (@pepper_chico)
@Herb: You wrote: “@Francisco: You wrote: "The answer contains good wisdom on const correctness, but got confused about the concurrency semantics meaning/correctness…" – could you elaborate on what you mean?” – First, I meant: “I got a little confused”, not the article, and, it’s nothing all special but just what one can derive from the general reaction to the article. The things related to internal/external synchronization, I think it may have not been explicit enough for the layperson, even more for the ones used to externally synchronized libraries. I wait for the synchronization wisdom from the mentioned GOTW to deal with this api contracts, etc. Read More »Comment on GotW #89 Solution: Smart Pointers by Chris Vine
“sink( new widget{}, new gadget{} ); // Q1: can you spot the problem?” The principal problem with this is that it will not compile, because unique_ptr’s constructor taking a pointer is explicit. sink(std::unique_ptr<widget>{new widget{}}, std::unique_ptr<gadget>{new gadget{}}); will compile but is not exception safe. Not only is the order of evaluation of the arguments unspecified, but the compiler is entitled to to construct gadget, and then before initializing the unique_ptr to take gadget construct widget, and only then construct the unique_ptr objects. Of course, it would be a very odd compiler which did it this way. Allowing this loose evaluation is in my view a defect in the standard, but I know that most others disagree. Read More »Comment on GotW #90: Factories by Ben Craig
After reading other people’s comments, I’ll agree with what I said, except for (3) :). Auto is the more likely answer, with unique_ptr being a runner up. Read More »Comment on GotW #6b Solution: Const-Correctness, Part 2 by edflanders
Regarding the guideline “Prefer passing a read-only parameter by value if you're going to make a copy of the parameter anyway…”: Does that apply to cases where need to copy to a specific location? E.g.: struct S { S(T t) : t_(t)) {} // two copies? void SetT(T t) { t_ = t; } // two copies? T t_; }; Does the guideline hold, or should you still pass T const& in these cases? Read More »Comment on GotW #90: Factories by Joe Gottman
For #4 you just return a Widget. If the class in non-polymorphic there is very little reason to go through the expense of a new and delete. Read More »Comment on GotW #6b Solution: Const-Correctness, Part 2 by Sean Lin
In old GotW 6, there is a guideline said: no longer true? If it is still prefered, get_point should return const point, right ? const point get_point( int i ) const { return points[i]; } Read More » Comment on GotW #90: Factories by jlehrer
WRT #4, I have had plenty of cases where a type was not polymorphic but did have an inheritance tree. The object factory returns a shared_ptr to the base for the reasons I described. If there is no sublcass of Widget, then, yes, I’d probably return a simple object. Read More »Comment on GotW #90: Factories by Neil
Re #4, the recommendation of returning Widget by value assumes that (N)RVO will kick-in or Widget’s move semantics are more optimized than its copy semantics. However, if Widget is composed of non-movable members (e.g. an aggregate/POD-type) then move will be no better than copy, so if RVO does not apply then the cost of copying Widget may be greater than new-ing up a Widget* and returning it via unique_ptr. Read More »Comment on GotW #90: Factories by Mikhail Belyaev
1. It. Returns. A pointer. Nothing here says if this pointer is to some internal data, or static variable, or a new-allocated structure or (even!) to a malloc-allocated structure. What are we supposed to do with it? We are supposed to read the source code. That breaks the entire encapsulation thing factories were originally ment to bring. And with all the variants I supposed, none of them really needs a pointer returned. Too bad LLVM exploits exactly this approach a lot. If it is a real newly-allocated polymorphic pointer, use std::unique_ptr. It has minimal tradeoffs (you just actually need the new-allocation) and fully expresses your intent. Even if some guy comes buy and calls release(), it’s not your fault. If someone needs to share it, he can always create a shared_ptr manually. If you need to share the pointer (for example, you keep track of all values elsewhere or your method is supposed to return an exact same pointer for a sequence of calls), use the shared_ptr. You can also consider using this if you are stuck with a need to create a uniform interface for both new-allocated, static and need-to-be-deleted-by-other-means values (that actually happened to me) and provide a dynamic deleter for each with a lambda. unique_ptr cannot do that as its deleter is statically-bounded. 4. If it is not really a polymorphic type, just return it by value and let compiler handle the rest unless you know for sure that the type cannot be efficiently move-constructed. Then we are back at #3. Read More »Comment on GotW #89 Solution: Smart Pointers by Marco
Thanks for the answer. I was referring to the reference counter. Good to know it is thread safe. We have had our own implementation of smart and weak pointers. Now we’re about to go to VS 2012, so I’m looking forward using all these great new features! Read More »Comment on GotW #90: Factories by Thibaud
For #3 if callers are using auto, they are using delete as well and you still have to remove them all. Read More »Comment on GotW #6b Solution: Const-Correctness, Part 2 by Arne Mertz
@edflanders: struct S { S(T t) : t_(std::move(t))) {} // at most one copy, one or two moves void SetT(T t) { t_ = std::move(t); } //at most one copy, one or two moves T t_; }; It’s in both cases one copy, one move, if the argument is an lvalue, and two moves, if it’s an rvalue. In the setter, t is move-or-copy _constructed_, while t_ is move-assigned. Read More »Comment on GotW #89 Solution: Smart Pointers by tr3w
If I’m not mistaken, the smart and weak ptr works like this: But here is the catch: If we used make_shared, the shared_ptr destructor can’t deallocate the area of the pointed object, only the weak_ptr will deallocate it (when it gets rid of the control block). Am I right? Read More »Comment on GotW #90: Factories by Elvis
I Agree with Ben except for point 3. load_widtget must return std::unique_ptr<widget> where widget is an pure abstract class. Read More »Comment on GotW #89 Solution: Smart Pointers by pip010 (@ppetrovdotnet)
well, instead: unique_ptr arg1(new widget{}); so here it goes. same exception-safety :) about: “It reduces allocation overhead, including memory fragmentation” same goes for locality? Read More »Comment on GotW #89 Solution: Smart Pointers by Marek
> The answer is no, because C++ leaves the order of evaluation of function arguments undefined… I think it is unspecified not undefined. Read More »Comment on GotW #89 Solution: Smart Pointers by Marco
@pip010: The two memory blocks will in general have very different sizes and may life in far far away areas of the memory because the system tries to minimize fragmentation. Read More »Comment on GotW #90: Factories by Sebastian Redl
I think Ben Craig’s initial instinct was more right. Comment on GotW #90: Factories by Laurent L.
Pretty good answers sofar, regarding polymorphism and ownership. I would add a question : Does the absence of “noexcept” tell the caller that failure management is performed through throwing an exception? In that case, all “widget*” solutions should be turned into “widget&” since the normal course of things guarantees that an object will be returned. And the smart pointers cannot be null, so they can be used safely without checking. IOW, any widget* solution should also say “noexcept”. Read More »Comment on GotW #89 Solution: Smart Pointers by pip010 (@ppetrovdotnet)
@Marco Comment on GotW #6b Solution: Const-Correctness, Part 2 by edflanders
@Arne Mertz: struct Matrix3x3 { double m_[3][3]; }; typedef Matrix3x3 T; Read More » Comment on GotW #89 Solution: Smart Pointers by pip010 (@ppetrovdotnet)
@Herb looking at VS2012 ans std::make_shared new _Ref_count_obj(LIST(_FORWARD_ARG)); //inside make_shared Comment on GotW #6b Solution: Const-Correctness, Part 2 by Elvis
void calc_area() const in my opinion must be double calc_area() const in this way we can avoid mutable area. Read More »Comment on GotW #89 Solution: Smart Pointers by Jeff Sullivan
Given that make_unique and make_shared can aggregate the memory allocation for the ref –counting together with that for the pointed at T, how does that play with class member operator::new() and operator::delete()? Depending on how this is managed you are either going to inherit the custom operators (which would be bad if it an allocator that assumes it only ever has to allocate sizeof(T) objects), or you are going to entirely circumvent efforts by a class designer to provide specific allocation facilities (which might lead to memory fragmentation and poor performance due to broken cache coherency, or simple failure to work if all members of a class are supposed to be in some shared memory pool). It would seem to be worthwhile pointing out that mixing classes with custom allocators together with make_shared or make_unique is a Bad Idea. To solve the problem for shared_ptr there is allocate_shared() that will take an allocator for generating shared_ptr which will get the same result as a custom operator::new()/operator ::delete() set (with a little rewriting) , However the only references I can find to "allocate_unique" are to Oracle DBMS systems…. Is this another candidate for the "Oops, we should have done that" C++14 list, or are there some subtleties I haven't considered? Read More »Comment on GotW #89 Solution: Smart Pointers by Eric Fortin
@Andrew Marshall weak_ptr gets notified when the object is deleted and will prevent you from accessing it where a raw pointer will let you do anything with the already deleted object sending you in undefined land. Read More »Comment on GotW #6b Solution: Const-Correctness, Part 2 by Herb Sutter
@Fernando: Sigh, you’re right. You know, that was my reading too and I wrote them out, then noticed that GCC let me get away with =default for the move operations and didn’t reread the standard. Since I had already written them out before switching to =default, the fix was as easy as hitting Ctrl-Y twice. :) Fixed mo betta. Read More »Comment on GotW #6b Solution: Const-Correctness, Part 2 by Herb Sutter
@edflanders: Yes, because you then take by value + move(param) as Arne noted. The only case where that’s not a good idea is when you have a type that’s expensive to move, such as std::array. I currently plan to cover this in a new GotW on general parameter passing, probably sometime in June or July. @Elvis: That wouldn’t allow area to be non-mutable. It’s mutable because it can be written to in const operations, which is still true if you restructure the code the way you suggest. As long as there’s a cached area that can be written to in const operations, it needs to be mutable, and synchronized as atomic or with an internal mutex. Read More »Comment on GotW #6b Solution: Const-Correctness, Part 2 by Herb Sutter
@Leo: Aha, thanks for spotting that leftover text from the original GotW. In several original GotWs I used to recommend considering returning a const value, instead of a non-const value, on the basis that it would help callers by letting them know when they accidentally modify a returned rvalue. I no longer think that’s good advice, especially since you want to move from rvalues which is a non-const operation, so I’ve been rooting it out of the GotWs as I go through, and I got rid of most of the references to that in this one but missed that one. Thanks, fixed. Read More » | ||||
| ||||
Thursday, May 30, 2013
FeedaMail: Comments for Sutterâs Mill
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment