For 2020 I'm doing a 1 C++ Best Practice per retweet thread! I wrote my first blog article about C++ best practices in 2007. In many ways I've been repeating myself over and over again for the last 13ish years. And very little of what I say is novel. Thread follows:
-
-
This really needs to be: ``` static constexpr std::array<int, 5> angles{-90,-45,0,45,90}; ``` The difference is beyond huge. https://godbolt.org/z/rQQnch See also:https://www.youtube.com/watch?v=xtf9qkDTrZE …
Prikaži ovu nit -
2: `const` Everything that's not `constexpr` Many people (like
@gregcons and@JamesMcNellis ) have said this many times. This does 2 things: 1. It forces us to think about the initialization and lifetime of objects, which affects performancePrikaži ovu nit -
2. Communicates meaning to the readers of our code. And as an aside, if it's a static object the compiler is now free to move it into the constants portion of the binary, which can affect the optimizer as well.
Prikaži ovu nit -
3: Follow the Rule of 0 https://en.cppreference.com/w/cpp/language/rule_of_three … No destructor is always better. Gives the compiler much more room for optimization. See also: https://www.youtube.com/watch?v=ayIJ4b6z-7g … `std::unique_ptr` can help with this, by providing a custom deleter.
Prikaži ovu nit -
4: If you must do manual resource management, follow the rule of 5 If you provide a destructor because `std::unique_ptr` doesn't make sense for your use case, you *must* `delete` `=default` or implement the other special member functions.
Prikaži ovu nit -
Homework assignment: implement your own `unique_ptr`. It's hard to get it 100% right. Write tests. Understand why the defaulted special member functions don't work. Bonus points: implement it with C++20's `constexpr` dynamic allocation support.
Prikaži ovu nit -
5: prefer scoped enums ``` enum Choices; enum OtherChoices ``` These two can easily get missed up and introduce things in the global namespace ``` enum class Choices enum class OtherChoices ``` cannot get mixed up without much effort.
Prikaži ovu nit -
@ciura_victor has given interesting stories about this in his CppCon talks about@ClangPowerTools Aside: `enum struct` and `enum class` are equivalent. Logically `enum struct` makes more sense, since they are public names. Which do you prefer?Prikaži ovu nit -
6. Prefer algorithms over raw loops Algorithms communicate meaning and helps us apply the "`const` all the things" rule. In C++20 we get ranges, which make algorithms easier to use.
Prikaži ovu nit -
7. Prefer ranged-for loop syntax over old loops ``` for(int i = 0; i < container.size; ++i) { // oops mismatched types } ``` ``` for (auto itr = container.begin(); itr != container2.end(); ++itr) { // oops, most of us have done this at some point } ```
Prikaži ovu nit -
``` for(const auto &element : container) { // eliminates both other problems } ```
Prikaži ovu nit -
8. Use `auto` in ranged for loops ``` for (const int value : container_of_double) { // accidental conversion, possible warning } ``` ``` for (const base value : container_of_derived) { // accidental silent slicing } ```
Prikaži ovu nit -
``` for (const auto &value : container) { // no possible accidental conversion } ```
Prikaži ovu nit -
9. Don't Invoke Undefined Behavior
@copperspice_cpp https://www.youtube.com/watch?v=XEXpwis_deQ … Ok, there's a lot that's UB and it's hard to keep track off, so we'll give some examples.Prikaži ovu nit -
10. Never test for `this` to be `nullptr`, it's UB ``` int Class::member() { if (this == nullptr) { // removed by the compiler, it would be UB return 42; } else { return 0; } } ```
Prikaži ovu nit -
People used to do this all the time, but it's always been UB. You cannot access an object outside its lifetime
Prikaži ovu nit -
11. Never test for a `&` to be `nullptr`, it's UB ``` int get_value(int &thing) { if (&thing == nullptr) { // removed by compiler return 42; } else { return thing; } } ``` It's UB to make a null reference, don't try it. Always assume a `&` is a value object.
Prikaži ovu nit -
-
12. Use the tools: sanitizers Address sanitizer, UB Sanitizer, Thread sanitizer can find many issues almost like magic.
@johnregehr recommends always enabling asan and ubsan during development.Prikaži ovu nit -
13: Use the tools: compiler warnings You have many many warnings you are not using, most of them beneficial. -Wall is *not* all -Wextra is still barely scratching the surface!https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Available.md#compilers …
Prikaži ovu nit -
14: Use the tools: static analysis cppcheck and clang-tidy are free and have integration with every IDE and editor today.
Prikaži ovu nit -
15: Use the tools: continuous builds If your project is not automatically tested regularly you will not be able to maintain quality. If you don't require 100% tests passing you will never know what state the code is in.
Prikaži ovu nit -
16. Use the tools: multiple compilers Support *at least* 2 compilers on your platform. Each compiler does different analysis.
Prikaži ovu nit -
17. Use the tools: automated tests You need a single command to run tests. If you don't have that your tests will not be run. * catch2 * ctest * doctest * gtest * boost::test You need to be familiar with these tools, what they do and pick from them.
Prikaži ovu nit -
18. Use the tools: build generators * cmake * meson * etc Raw make files or visual studio project files make each of the things listed above too difficult to implement. Use a build tool to help you with maintaining portability across platforms and compilers.
Prikaži ovu nit -
19: Use the tools: Package managers * vcpkg * conan
@conan_io * hunter * etc Also help with maintaining portability and reducing load on the developers. Videos here:https://www.youtube.com/watch?v=9cCQHJ-cNHY&list=PLs3KjaCtOwSZ2tbuV1hx8Xz-rFZTan2J1&index=118 …Prikaži ovu nit -
20: Prefer `auto` in many cases. First off, I'm not an Almost Always Auto person, but let me ask you this: What is the type of `std::count`?
Prikaži ovu nit -
My answer is "I don't care." ``` const auto result = std::count( /* stuff */ ); ``` avoids unnecessary conversions and data loss. Same as ranged-for loops. Also, `auto` requires initialization, same as `const`, same reasoning for why that's good.
Prikaži ovu nit -
21: Constrain your template parameters with concepts (C++20) This will result in better error messages (eventually) and better compile times than SFINAE. Besides much more readable code than SFINAE.https://www.youtube.com/watch?v=dR64GQb4AGo …
Prikaži ovu nit -
22: Prefer `if constexpr` over SFINAE See #21. SFINAE is kind of write-only code. `if constexpr` doesn't have all the same flexibility, but use it when you can. See Practical C++17https://www.youtube.com/watch?v=YePHP4aIc1g …
Prikaži ovu nit - Još 26 drugih odgovora
Novi razgovor -
Čini se da učitavanje traje već neko vrijeme.
Twitter je možda preopterećen ili ima kratkotrajnih poteškoća u radu. Pokušajte ponovno ili potražite dodatne informacije u odjeljku Status Twittera.
)