| ||||
| Comment on GotW #6a Solution: Const-Correctness, Part 1 by mttpd
Regarding the shared variable question–the following note from the standard (17.6.4.10/[res.on.objects) may also be of help in underscoring the importance of this concepts: // Personally, I also like to think in terms of the shared-vs.-private distinction in the sense its used in OpenMP, but perhaps this is somewhat too API-specific for this question. Read More »Comment on GotW #5 Solution: Overriding Virtual Functions by javierestrada
Herb, In the guideline: Guideline: Prefer to have a class contain only public virtual functions, or no public virtual functions (other than the destructor which is special). It is unclear that protected virtual functions are possible and useful (protected interface) common in streams and a design pattern itself. Now, “no public virtual functions” can cover this usage of virtual functions, but it’s subtle. When you say: “A pure abstract base class should have only public virtual functions. …” Section 10.4 [class.abstract] only goes as far as defining an abstract class (neither pure nor “impure”) as a class with at least one pure virtual function. Since you can’t instantiate them, it follows that they can only be used as base classes. I think the sentence could be clearer if it were reworded as: “An abstract class with only pure virtual functions should have those functions be public.” This leaves open cases where you want an abstract class to have a public interface where it can control pre/post conditions and then call a protected virtual function on a derived class (I use this technique extensively in large telephony frameworks in C++ and C#): class Call { public: Drop() { // check preconditions, acquire locks, etc., OnDrop(); // check postconditions, release locks, etc. } protected: virtual void OnDrop() = 0; ... }; class MyCall : public Call { ... protected: override void OnDrop() { ...} }; Regards, –Javier Estrada Read More »Comment on Lost two comments by jlehrer
Me too. I’m getting post notifications and some comment notifications twice. :( Read More »Comment on GotW #6a Solution: Const-Correctness, Part 1 by Matthew Fioravante
Suppose you have a container like std::map and you want to populate it once at startup and then have multiple threads do lookups later. This is easy enough to accomplish with the new definition of const. Just create the map, add stuff to it, start your threads, and then expose only a const reference to it to the threads. Since the threads only use const methods, the lookups are guaranteed to be thread safe without requiring the callers to use mutexes or any other external synchronization. One could imagine an implementation of std::map possibly moving nodes around the tree during lookup as an optimization. With const, this behavior would either be prohibitied or would have to be internally synchronized. But what if you want the threads to be able to modify the widgets? Assuming the widgets modify operations themselves are properly synchronized in some other way, this is perfectly safe as the internal operations of the std::map (or any other key/value mapping data structure) depends only on the keys, not the values. Unfortunately the const version of find() returns a const_iterator which only provides access to a const version of the widget. The only way around this problem is to either do a const_cast on the const widget& or do some kind of indirection by storing Widget* in the container or some other iterator/index into another storage container for the widgets. It seems like const is a little too strong here, in that the constness of the container also “infects” the elements of the container. Sometimes this is what you want, sometimes not. I think in C++98 it made a little more sense but now that const has also gained “thread safe” semantics this weaker form of const may be desirable. Was this usage pattern ever considered for std::map/unordered_map and other containers? One could even imagine doing the same with a vector, where you wanted to allocate a bunch of object contigously in memory beforehand and then read and modify them later without being able to insert or remove anything from the vector. I don’t think any sane implementation of vector::operator[]/vector::at() would do anything more than a bounds check and array reference but it still would be technically not standards compliant to read from a std::vector without either using a mutex or a const method. I’m thinking the best solution for this problem for now would be to wrap the container in another class which calls the const methods for lookup and const_cast’s the values to non-const before returning them. Any thoughts? Read More »Comment on GotW #5 Solution: Overriding Virtual Functions by Fernando Pelliccioni
Hi Herb, I think auto pb = std::unique_ptr<Base>{ std::make_unique<Derived>() }; is too verbose. Unique is repeated… How about this library solution for C++14 or C++17 ? auto pb = make_unique_poly<base, derived>(); Regards, Comment on GotW #6a Solution: Const-Correctness, Part 1 by mttpd
Incidentally, my second comment is a nice example of Muphry’s law (spelling intentional) in action ;-) @Herb: any chance for an edit-own-comments feature? :-) Read More »Comment on Lost two comments by macs85
Don’t know whether this is of interest for you, but I’m constantly getting post notifications twice. Already checked the subscriptions, seems there is only one. So, maybe this is somehow related? Cheers, P. S.: GOTW teaches so much, thanks! ;) Read More »Comment on GotW #6a Solution: Const-Correctness, Part 1 by Herb Sutter
@mttpd, @jlehrer: Fixed, thanks. Read More »Comment on GotW #6a Solution: Const-Correctness, Part 1 by Chris Vine
“Starting with C++11, const on a variable that is possibly shared means read-only, safe to read concurrently without external synchronization.” This is only true if no threads have access to the shared object in a non-const context. If a non-const shared object is passed to a library function by reference to const, without synchronization that function’s read on the object is not safe if another thread might modify it. What I think this should say is that “const means read-only, and safe to read concurrently without external synchronization if no other thread has write access to the shared object concerned in a non-const context”. Read More »Comment on Lost two comments by Amali
Clicking on Comment and See all comments from the posts I received in my Inbox gives “page not found error”, which was working before. Now, to add any comments, one has to visit your webpage, open that particular post, and add comments. I hope this error will be fixed, too. Read More »Comment on GotW #6b: Const-Correctness, Part 2 by Nathan Ridge
add_point() should take a point by nonconst value, and move it into the vector. get_point() should be const. Its parameter needn’t be const. get_num_points() should be const and should return size_t. get_area() should be const. area should be mutable. calc_area() should be const and should use const iterators into the vector. operator+ should take lhs by nonconst value (and then not copy it again into ‘ret’), and rhs by reference-to-const. f should take its argument by reference-to-nonconst, since it modifies it. Of course there’s no need for the const_cast then. g has a const in a place where it’s implied (and not allowed explicitly) – after a reference. That should be removed. Otherwise it’s fine. h is fine, the toplevel const just means h promises not to change its argument poly to point to a different object. However, as with get_point(), there is little point (no pun intended) to making a parameter toplevel const. Read More »Comment on GotW #5 Solution: Overriding Virtual Functions by Ricardo Costa
@GeoffW You may want to check this article http://akrzemi1.wordpress.com/2012/09/30/why-make-your-classes-final/ and especially the discussion in the comments section. @rhalbersma As jhasse pointed out, you wouldn’t be able to shadow variables: auto x = 1; { auto x = 2; } // x == 1 again Read More » Comment on GotW #5 Solution: Overriding Virtual Functions by Róbert Dávid
@Fernando Pelliccioni: std::unique_ptr<Base> pb = std::make_unique<Derived>(); If you are using ‘auto’ for variables that have the same type as the initializer consistently, it will be obvious that there is a conversion here, and auto pd = std::make_unique<Derived>(); has no conversion. Read More »Comment on GotW #6b: Const-Correctness, Part 2 by JL
- change add_point() signature to add_point(const point &pt) additional notes: Comment on GotW #4 Solution: Class Mechanics by Luca Risolia
@Herb, I apologize if this has been already suggested by others, but what about recommending the following version of operator+() other than the one you propose in the final version of the complex class: complex operator+( const complex& lhs, complex&& rhs ) { rhs += lhs; return rhs; } Compared to the original solution, this way an extra-copy can be avoided when a temporary object is passed as argument to rhs and the const ref lhs is bound to an lvalue. Read More » | ||||
| ||||
Saturday, May 25, 2013
FeedaMail: Comments for Sutterâs Mill
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment