15 ms·
C++ Core Guidelines
- inglor 11y agoIt's amazing how many people get these core principles wrong. I recently visited a C++ shop who hasn't even heard of RAII and don't use smart pointers or standard containers. What a nightmare. It's great to see C++ getting an ecosystem and Bjarne's excellent writings help a lot.
- seivan 11y agoI'm still learning c++11, but the framework I am using is not using smart pointers. It uses a single auto release pool with reference counting. Coming from Obj-C, I kinda like it but not sure what the downsides are so far into c++. Jonathan Blow has a good point about smart pointers being a poor solution tacked on the language. As it wraps your class in another class and becomes kinda ugly.
- GFK_of_xmaspast 11y agoIf you're still learning c++, how do you know they're a poor solution?
- nadams 11y ago> how do you know they're a poor solution After using Java, Python, C# and other languages. Smart pointers aren't really that smart. I'm not saying garbage collection is the solution - but smart pointers aren't a silver bullet.
- mlindner 11y agoGarbage collection isn't a very good solution. They're often implemented poorly (the only good one being Go's) and they're slow. Garbage collection also necessitates a runtime environment to keep track of the data. What is not smart about smart pointers? std::shared_pointer implements reference counting just as OP describes.
- nadams 11y ago> Garbage collection isn't a very good solution. I clearly didn't say it was. > They're often implemented poorly (the only good one being Go's) and they're slow. Do you have any evidence to support that? From my experiences and tests C# has been on par with C++ [1]. Of course it might be slightly slower but not enough for me to dismiss it. Java I think is a little bit slower - but my problem with Java is its memory requirements. > Garbage collection also necessitates a runtime environment to keep track of the data. Assuming they do this in a separate thread and you have an OS that schedules threads/processes in a sane way and the GC doesn't need to interact with the main thread - you should never notice a performance hit in your application. > What is not smart about smart pointers? They don't track the actual memory usage. John Carmack implemented his own version of memory management for both Doom 3 [2] and Doom 3 BFG [3] presumably so he could get debugging information that isn't available with the C++11 smart pointers. I've implemented something similar to Doom 3's heap where I track the line and file of where the heap memory was allocated. The one thing I've noticed about developers today is that they have become lazy. Yeah - smart pointers will work correctly in simple cases and 90-99% of the time but it was written by humans so it may have bugs in it. Most C++ developers today refuse to run valgrind because they just assume their program doesn't leak memory when using shared_ptr/unique_ptr. I have personally found memory leaks in pretty popular open source projects. I would have told them about it - but I've found most C++ communities to not welcome new people and their ideas. [1] http://www.codeproject.com/Articles/212856/Head-to-head-benchmark-Csharp-vs-NET http://www.codeproject.com/Articles/212856/Head-to-head-benc... [2] https://github.com/TTimo/doom3.gpl/blob/8047099afdfc5c973faa67a04f601a014de0fa73/neo/idlib/Heap.h https://github.com/TTimo/doom3.gpl/blob/8047099afdfc5c973faa... [3] https://github.com/id-Software/DOOM-3-BFG/blob/9c37079c16015fc58de29d3de366e0d93dc11f8a/neo/idlib/Heap.h https://github.com/id-Software/DOOM-3-BFG/blob/9c37079c16015...
- GFK_of_xmaspast 11y ago> John Carmack implemented his own version of memory management for both Doom 3 [2] and Doom 3 BFG [3] presumably so he could get debugging information that isn't available with the C++11 smart pointers. Is this the same "Doom 3" that came out in 2004, a full seven-ish years before c++11.
- seivan 11y agoYou're right, I'll rephrase: I agree with Blows point on it so far. But I am pretty biased, I loved reference counting, and ARC just made it more awesome. I want ownership, I point strongly. I don't care about ownership, I'll have a weak ref and that's it.
- RotsiserMho 11y agoYou just described std::shared_ptr and std::weak_ptr. I recommend doing some more reading on the subject.
- seivan 11y agoThanks, I will! But it doesn't change what Blow said, and what I agreed with. It becomes ugly and takes more space than I need to. My class becomes weak_ptr and what I want to use becomes the template. You should also look into his talk about c++ and its weaknesses.
- jschwartzi 11y agoIn the embedded world, this is the rule not the exception.
- RotsiserMho 11y agoIn my experience in the embedded world it is at least recognized that RAII should be used. It is fast becoming the exception not to use RAII and now that smart pointers are in the standard, the same goes for them.
- revelation 11y agoBecause, in the embedded world, you better have a good fucking explanation of why you are using dynamically allocated memory. Bring a formal proof that you won't go out of memory. Attach additional information on how you wrote an allocator that runs in constant time and does not risk taking it's sweet time to scan a huge area of memory. Sure, it's all O(n), but who cares if determining when you are going to hit the huge n case is equivalent to solving the halting problem. Of course, at this point, the hassle simply means you don't use dynamic memory.
- deleted 11y ago[deleted]
- jschwartzi 11y agoI agree with you regarding dynamic allocation. RAII is an orthogonal concept to dynamic allocation though, and it's actually beneficial because it forces you to declare all your resources up front or die. Even in the case that you're using an STL container, it's probably a hash table or tree data structure, and you're probably populating it at initialization time with a defined quantity of items. In that case, even if it's doing heap allocation it's effectively static allocation.
- bluecalm 11y agoOr you know, maybe they have different view on these things. There are good programmers out there who don't use RAII or smart pointers and think that most of this modern stuff is just added cruft for little gain. Standard containers are nice but if performance is your problem you often need to re-implement them anyway and if it is not then maybe you could have done it in the higher level language in the first place. Whatever float your boat (and your particular niche).
- deeringc 11y agoI don't see many valid reasons why you wouldn't want to use RAII patterns for any sort of resource management. I would go as far as saying that if you aren't doing so, you're probably doing it wrong. Having said that, I'd be genuinely interested to hear some resource managment sceanrios where you're better off not using RAII.
- CamperBob2 11y agoRAII requires you to use exceptions or equally-ugly hacks to detect constructor failure. Some people (myself included) have a problem with that.
- to3m 11y agoYou can end up needing a lot of different RAII types, which can get a bit annoying. If you're trying to interface with anything that wasn't written with RAII in mind - e.g., any library that tries to be C-compatible - this is pretty much inevitable. In theory, doing without is a huge problem, because you're running the risk of resource leaks and stale identifiers - but in practice, neither is a huge problem. Picking these sorts of bugs out has been pretty simple in every project I've worked on. I've had far more heartache from the bugs stemming from RAII-type mechanisms holding on to resources longer than they should, than I've had from fixing bugs caused by resource leaks or stale resource identifiers.
- Quiark 11y agoWith std::unique_ptr (you can set the deleter) and ScopeGuard you don't need to create new types for every type of resource. I respectfully disagree with leaks not being a problem.
- yarrel 11y agoI'm suspicious of anyone who uses smart pointers without being able to discuss the trade-offs. Likewise the STL and Boost('s smart pointers and containers). RAII on the other hand, totally.
- dvt 11y agoLook son, a RAII zealot in the wild!
- mellery451 11y agomost of this is stuff Herb (and others) has been promoting for years...and It's great to see it codified in one place.
- something123 11y agoThis is definitely a step up from having to look through his blog (where a lot of the old stuff is waiting to be updated to C++11)
- ilurk 11y agoIt's posts like these that remind me how hard it is to write idiomatic/correct C++, when compared to something like Python or Java.
- Retra 11y agoI've only really ever made one project in C++, and I spent a good deal of time learning the "right way" to make different kinds of constructors. And all I could think is, if there is a "right way" to do it, then why isn't it the default? Why am I actually doing research on how to write boilerplate? It's because C++ is a disaster. Everyone likes to point out that you should only use a subset of the language. But that's not my experience with C++; only using a subset makes you vulnerable to all the problems associated with not understanding the actual language that is implemented, not just the subset you wanted it to be.
- Joky 11y agoThis is not completely false, but clearly the view of someone who does not understand C++. Yes C++ carries decades of history, but since C++11 even if you can still make use of this you don't have to cope with. It is perfectly fine to use only a subset of C++, you just have to use the right one and this is what this documentation is about IMO. Yes you have to understand the language to be efficient with it, but it is a language that allows high performance and maintainable large scale software. Python was cited as an example in this thread and I don't get it. There a many ways to write the same thing in Python and I always end up spending more time looking on the web to figure out what is the "Pythonic" way.
- jlarocco 11y agoThe difference is that not being "Pythonic" is a style issue. A Python guru may scoff and point out that you could write the same thing more elegantly some other way, but most of the time the performance is the same, and the behavior is correct either way. On the other hand, not following some of these C++ guidelines can mean your code is subtley broken and depending on undefined behavior, or leaking memory, or accessing something it shouldn't, etc. I write C++ at work. We all know the language pretty well. We send people to conferences. We have somebody presenting at CppCon next week. We still get bitten by C++ more than you would belive.
- aurelian15 11y agoIt is great to have such a collection of rules and I hope they will be integrated into some easy-to-integrate static code analysis tool (as mentioned in the introduction). Maybe this will help people to transition to more modern C++ and to avoid some pitfalls (e.g. forgetting the "noexcept" for move constructors/assignments). However, in some respect this list also shows what is wrong with C++: The fact that you even need such a huge set of rules to write safe and efficient code is somewhat unsettling. I'd rather hope a new version of the language standard would at least allow to hide deprecated constructs behind a "safe/unsafe" pragma.
- something123 11y agoIt always seemed to me that it should be relatively not difficult to write some kind of language that limited you to the "right" way of doing things and that compiled down to C++ You could: - prevent people from using deprecated features - immediately remove TONS of boilerplate - automatically generate header files from the cpp's - have high level keywords that would generate design patterns for you (no more having to re-implement a Visitor for the first time that year and having to spend a day debugging it) At the same time you could still leverage C++ libraries and when you do need to write an allocator or do some fancy diamond inheritance friend method templating magic shenanigans you could always drop back down to C++ EDIT: What I find kind of amusing is that with time you can do more and more of these things through Visual Studio's magical "wizards" and checkboxes (maybe it's the same for the other IDEs.. not sure), but ofcourse it's rather silly, clunky and slow to use. In the latest version you can finally make matching declarations/definitions with a couple of clicks - saves a lot of the mildly frustrating copy/past'ing!
- kllrnohj 11y agoWhat you're describing basically already exists, it's Rust.
- throwawayaway 11y agoTHIS. ZING. fuck sake.
- mmphosis 11y agoI first started looking at this when Cfront by AT&T Bell Telephone Laboratories came out. Let me know when the language stabilizes and maybe I'll take a look at it again.
- laichzeit0 11y agoDo you feel the same way about the English language?
- criddell 11y agoExactly. I hear Latin is pretty stable these days.
- laichzeit0 11y agoYeah, Classical Latin is pretty stable. Try use it in a modern conversation and you'll realize how painful that property is. Anything that's made of plastic, uses electricity, steam, actually any original idea in the last 300 years would require inventing some neologism just so you could talk about it.
- JoeAltmaier 11y agoIm not so sure? The word 'plastic' existed before plastic did. Does Latin not have a word for that property? And so on.
- laichzeit0 11y agoI think you might still end up with something like the Lexicon Recentis Latinitatis [1] maintained by the Vatican. And unless you "make up" neologisms you'll end up with stuff like "timer - instrumentum tempori praestituendo" which would be extremely tedious to use in a conversation. Purists might argue that it would be awesome if we could make grammar "stable" though. It's an interesting thought. [1] http://www.vatican.va/roman_curia/institutions_connected/latinitas/documents/rc_latinitas_20040601_lexicon_it.html http://www.vatican.va/roman_curia/institutions_connected/lat...
- ubercow 11y ago>This document is a very early draft. It is inkorrekt, incompleat, and pµøoorly formatted. It's the little things in life that make it so great.
- a_e_k 11y agoThat's a bit of a running joke. It's funnier in the working draft PDFs of the standard, e.g.: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n429...
- pjtr 11y agoI've first seen this in some GCC internals document [1] in 2008. There "incomplet" was incomplete and "incorrekt" was incorrect. [1] https://gcc.gnu.org/onlinedocs/gccint/Deficiencies.html https://gcc.gnu.org/onlinedocs/gccint/Deficiencies.html
- re 11y agoI'm not sure if this is a completely intentional joke or actually mojibake—if encoded as Latin-1 and decoded as UTF-8, you get "pµøoorly formatted."
- enqk 11y agoThe more I develop in C++, the more I wish I had a very restructure transpirer that would remove some of its most silly constructs or switch ite base defaults around. Some examples: - making all constructors explicit and adding an implicit keyword instead for that rare case - automatically generated !=, <=, >= etc from == and < (with an explicit override when you want to be silly) - removing some of the redundant syntaxes (const positioning, typedefs vs using etc - removing the class keyword
- tragomaskhalos 11y agoYou can easily do your != et al from < thing by using CRTP inheriting from a 'comparable' template class that provides the implementations. Sort of thing that should be in std really.
- ourson 11y agoIt is. using namespace std::rel_ops;
- ant6n 11y agoIt looks like this isn't attached to the class definition, but rather to the uses. I.e. for every use of a class that only defines ==, <, you have to include rel_ops. But then it would basically provide the other comparators to all classes, maybe not something you'd want.
- Rexxar 11y agoYou can use "boost/operators.hpp" for operators generation.
- unfamiliar 11y agoI would make const the default and require a `mut` keyword.
- okasaki 11y agoI'm only a bit in but I've already found myself disagreeing with some of these for example drawline(int,int,int,int); // obscure drawline(Point,Point); // clearer this is only "clearer" until you find yourself at the very common case where you use several libraries where each defines its own "Point". Now you're writing something like drawline(Point(vec.x1, vec.y1), Point(vec.x2, vec.y2)) Pretty ugly! And of course drawline(Point, Point) isn't clearer at all imo. What's the coordinate system? What are the units? Any performance notes on this function? Etc. I'll be checking the documentation the first time anyway. void do_something(vector<string>& v) { string val; cin>>val; // ... int index = 0; // bad for(int i=0; i<v.size(); ++i) if (v[i]==val) { index = i; break; } // ... } this is shown to be inferior to the find() version. Again, it's only inferior until the very common case where you're doing something else with the index, which is pretty common during debugging. Then you'll be rewriting the above "bad" version anyway. Similar problems other higher order functions like for_each().
- TillE 11y agoI don't enjoy converting stuff between different formats for different libraries either, but sticking associated bits of data together really does make sense. With a function that just takes four integers, you can't easily distinguish between two Points or a Rect, for example. Plus, a lot of problems are solved by namespacing and something like this: typedef std::tuple<int, int> Point;
- Jyaif 11y ago> What's the coordinate system? What are the units? Good question. Where are you going to look that up? In the documentation of drawline? Should drawrect, drawcircle, etc..., also include documentation about the coordinate system/units? Of course not, that information should be centralized. That's where Point come in. And that's just a detail, the main advantage of using a class is that is abstract details. In the Point class, you may want to switch from int to int64_t without having to revisit all the methods.
- 11y ago
- acconsta 11y agoI wonder how many of these could be implemented in clang tidy: http://clang.llvm.org/extra/clang-tidy/index.html http://clang.llvm.org/extra/clang-tidy/index.html
- something123 11y agoFrom the introduction: "The rules are designed to be supported by an analysis tool. Violations of rules will be flagged with references (or links) to the relevant rule. We do not expect you to memorize all the rules before trying to write code. The rules are meant for gradual introduction into a code base. We plan to build tools for that and hope others will too." So it sounds like they will be introducing some tooling in the near future. It'd be nice if they leveraged existing tools (like clang-tidy)
- wnissen 11y agoOne exception "NL.1: Don't say in comments what can be clearly stated in code Enforcement: Build an AI program that interprets colloqual English text and see if what is said could be better expressed in C++." Pretty funny stuff for a style guide.
- mreiland 11y agoP.4 mentions using variant, but I couldn't find any information on this. Does standard C++ have a built in variant now? If so, could someone link me to a resource?
- RotsiserMho 11y agoThere's a proposal to include it in C++17. See also: https://www.justsoftwaresolutions.co.uk/cplusplus/standardizing-variant.html https://www.justsoftwaresolutions.co.uk/cplusplus/standardiz...
- mreiland 11y agothank you, all I could find were references to boost or home grown solutions, it makes sense now :)
- dunkelheit 11y agoI must confess I am tired of all these guidelines. I mean I have learned C++ once, gone through the ordeal of learning all the best practices, memorizing all the gotchas etc. And now the language just got bigger. New features arrived along with new unexpected gotchas. Scott Meyers has written a new book and all is well. Except that the more C++ I write the more I yearn for something simpler with less arbitrary rules to memorize.
- humanrebar 11y ago> And now the language just got bigger. If you want to master the whole thing, sure. But for in-the-trenches application devs, it's a lot simpler now. For example, if you want to disable copying: MyClass(const MyClass &) = delete; That's a lot simpler than knowing the declared-private-but-not-implemented trick. There's a decent-sized list of these simplifications, especially using 'auto' instead of remembering the 102 characters necessary to describe the return type of 'begin()'.
- dunkelheit 11y agoYes, some of it is great and the ability to write for (const auto& item: collection) { is probably my favorite feature of C++11. Ironically it makes the recommended approach of using standard algorithms with lambdas look abstruse in comparison. Considering your example, I still feel that inheriting from boost::noncopyable is the cleanest way to declare the class noncopyable. It feels almost like a language keyword! But the amount of new gotchas is significant too. In particular to use move semantics effectively you have to be aware of such obscure things as xvalues, std::move_if_noexcept and rules for autogenerated move constructors. The fact that the committee itself did not get it right on the first try speaks for itself.
- jheriko 11y agostarted losing me at exceptions. the philosophy bit is quite nice, but seeing auto in the example... not for me. not even close. its a shame we are ruining C++. can't we just have something better... :/
- Pyxl101 11y agoWhat's wrong with auto in the example? (I didn't downvote you, but I think you're being downvoted because you said that C++ is being ruined without explaining why these suggestions are problematic or arguable, which doesn't add to the discussion)
- jheriko 11y agonothing, and in fact the idea behind auto is sound if you take it out of the context of C++. in the context of adding to such a powerful and already overloaded with features language it creates subtle gotchas... i've hit them and seen them being hit, so i don't use it. the usual examples of it shortening iterators are not a problem i have day to day... i also find arguments about typing less and avoiding typing mistakes seem to miss what programming is really about in the wild. i spend 20% of my time at absolute most actually converting my ideas into code and typing them into some document...
- rleigh 11y agoauto can be a great aid to readable and maintainable code. It can also be used to obfuscate when not used in moderation. for(const auto& elem : container) is vastly more readable than for(my_long_type<specialised_type>::const_iterator iter = container.begin(); iter != container.end(); ++iter) I recently had to rewrite some C++11 code to C++98 to fit into a project. Using nothing but auto and range-based for loops, it nearly doubled in size by switching back to the older more verbose syntax. So long as you don't go to the other extreme, these have much value.
- jheriko 11y agoits also a death trap in winrt when combined with templates in the way they do. debugging that typoing a callback signature results in nothing happening in asynchronous code controlled by the ppl task library is a massive pain for even an experienced programmer. auto is nice in principle, but it is introduced in such a powerful and dangerous environment that there are subtle gotchas in real world use cases. including targetting a major platform by using its system libraries. programming is about thinking, not typing and programmer convenience. i don't enjoy auto for that reason either... if it were to save me time it would be little. i find using the stl algorithms and avoiding the nasty stl iterator pattern like the plague means the problem you describe just doesn't exist for me as a day-to-day case.
- raincom 11y agoAll these guidelines are good for those who have been in C++ trenches for a while. For others, it will become another list, a list similar to what non-native English speakers have to learn by rote in order to predict the pronunciation of English words. We have Scott Meyer's effective c++, more effective c++, effective STL, effective STL, modern effective c++. I have read Bjarne's "A tour of C++", which is a good one to read. Also read his "design and evolitution of C++", which gives rationale for what we see the ugliness of C++. I think we need a small book that describes the history of C++ until now, such a book can help us to remember "C++ core guidelines". This is similar to how great vowel shift in the history of Enlgih langauge helps us to see deeper patterns in English pronunciation. I hate a bunch of guidelines, without historical explanations, because such guidelines are very hard to pin to one's brain unless one is working in hardcare C++ everyday. Maybe, this sounds like playing Piano scales:)
- hit8run 11y agoThat's what I really value about Go: gofmt and very good linting that embraces best practices. I know C++ is way more complex but for someone starting out it seems impossible to code in the "right (tm)" style.