[HN Gopher] C++ by Example
___________________________________________________________________
C++ by Example
Author : synergy20
Score : 204 points
Date : 2022-09-22 12:52 UTC (10 hours ago)
(HTM) web link (cppbyexample.com)
(TXT) w3m dump (cppbyexample.com)
| frozencell wrote:
| They should do: C++ by Problems.
| jdlyga wrote:
| I always loved C++ as a language. Most of the use cases for it
| nowadays are when performance is key, and people use python for
| everything else. But I miss the structure that C++ provides
| without the heavy hand that Java and C# require. I definitely do
| not miss memory leaks and investigating core dumps though.
| ncmncm wrote:
| Good news, with modern usage, memory leaks are a thing of the
| fast-receding past. Occasion to investigate core dumps is
| lately vanishingly rare. (I have spent strictly more time
| filing compiler bug reports, in recent years, than debugging
| memory usage violations.)
|
| Today, it is fun to code in C++. Restricting it to performance-
| critical uses would be a bad mistake. Displacing C with
| simpler, more reliable, often faster C++ is an easy choice, but
| reaching for C++ in place of Python is also often a great idea.
| TillE wrote:
| Yeah I literally have not had a single memory leak since I
| started using unique_ptr and shared_ptr everywhere.
|
| I have had a couple resource leaks with C APIs, though even
| they could have been avoided with unique_ptr and a custom
| deleter.
| [deleted]
| scaredginger wrote:
| Hmm, not sure I'd trust this. I took a look at the shared_ptr
| page and didn't see it mention reference cycles or weak_ptr
|
| https://cppbyexample.com/what_is_shared_ptr.html
| MauranKilom wrote:
| The site is very clearly not a complete guide, and has to leave
| out 90% of what a competent C++ programmer _should_ know about
| any given topic (in order to remain accessible). I mean, the
| word "undefined" only appears in two of the examples.
|
| But I'd say it doesn't teach any _bad_ (or outdated) habits,
| which is a big step up from most tutorials /articles/SO
| answers.
| planede wrote:
| I have an other gripe with that page:
|
| > [about std::make_shared] This function is useful because
| objects might throw exceptions during construction and if they
| do we still need to call delete on the pointer we received from
| new otherwise we will leak the pointer.
|
| This is oversimplified and just plain incorrect. There was
| never a possibility that a statement like `auto sh_ptr =
| shared_ptr<Widget>(new Widget);` could leak.
|
| However possibility for leak existed for calls like
| `foo(shared_ptr<Widget>(new Widget), shared_ptr<Widget>(new
| Widget))`, because evaluation of function arguments were
| unsequenced. This hole was fixed in the language in C++17,
| where function arguments became indeterminately sequenced.
|
| And possible advantage for `make_shared` is the shared
| allocation for the control block and the object. It is not a
| clear advantage, as remaining `weak_ptr`s keep the whole
| allocation alive, even after the object itself is destroyed.
| But I wouldn't include this to a tutorial.
|
| One annoying place where you can't use `make_shared` and
| `make_unique` is for invoking private constructors, even in a
| context where you could use the private constructor directly
| (like a static factory function within the same class). Since
| `make_shared` and `make_unique` are typically not friends of
| your class, they can't call the constructor indirectly. There
| are some workarounds for this, but the easiest way is just to
| use `new` here, it's fine.
| deadbeeves wrote:
| It seems more robust to just make std::make_*() a friend
| function than to pepper the code with news.
| MauranKilom wrote:
| That only works if `std::make_*` is actually where `new` is
| called. It could just as well be called deeper in some
| library implementation detail like
| `std::__gnu_cxx_v3::__construct_as(...)` (made up example),
| in which case you're SOL.
| deadbeeves wrote:
| Hmm... Good point. I don't think it's a portable
| solution.
| planede wrote:
| I agree. If you can, just use the make_* functions. It also
| reduces needless repetition. For `make_*<Widget>(args...)`
| I need to write the type once, for `*_ptr<Widget>(new
| Widget)` I need to write the same type twice. Not counting
| cases for `Base/Derived`.
| ur-whale wrote:
| Where's the template metaprogramming section?
|
| What about the double bracket operator?
|
| etc...
|
| Or, to put it another way: very nice website for basic exposure
| but mostly demonstrates very basic stuff.
| donedealomg wrote:
| sudosysgen wrote:
| I don't see what special about double brackets? It's just
| calling the operator again on the result, completely intuitive.
| edflsafoiewq wrote:
| He means attributes, eg [[nodiscard]]. Of course you
| shouldn't call them operators.
| MauranKilom wrote:
| See, I assumed they meant the >> operator. That used to
| (long ago) be cause for grief in e.g.
| std::vector<std::vector<int>> where the parser would see a
| >> operator instead of two closing angle brackets (since
| fixed by changing the grammar).
| tialaramex wrote:
| So, there are four things which might get colloquially
| called "Brackets", they each have other names but...
|
| (Round) brackets are Parentheses
|
| {Curly} brackets are Braces
|
| <Angle> brackets are Chevrons
|
| [Square] brackets are often just Brackets
|
| Ah, so there's the problem. Now, this actually also
| differs depending on English variant. In England it would
| be pretty normal to say "Brackets" and mean Parentheses,
| whereas in the US you'd mean the _square_ brackets. Some
| English speakers outside the US might call the Square
| Brackets "Crotchets" to distinguish them, not so many.
| US English dominates in technology.
| jvanderbot wrote:
| Yeah, it's fairly basic, and most of this is in the usual c++
| docs like cppreference.com
|
| But... Is template meta-programming a required feature of a C++
| dev?
|
| double-bracket is ... an edge case of usual [] overloading,
| isn't it?
| ur-whale wrote:
| These are just examples to make a point.
|
| And: https://arne-mertz.de/2016/12/modern-c-features-
| attributes/
| ncmncm wrote:
| It has been years since I was tempted to template
| metaprogramming. It is a specialist technique being made
| redundant by straightforward language features that compile
| much faster.
| stonemetal12 wrote:
| Templates are a major feature of the language, leaving it out
| seems a little weird.
| sva_ wrote:
| These? https://cppbyexample.com/templates.html
| ur-whale wrote:
| That's just templates.
|
| I'm talking about stuff like this:
|
| https://en.wikipedia.org/wiki/Template_metaprogramming#St
| ati...
| d_tr wrote:
| Looks like an ongoing work so more will probably be
| available in the future. I see an example for templates.
| Template metaprogramming is more advanced but would be nice
| to include.
| DethNinja wrote:
| So far I've used six languages to build everything from web apps
| to desktop applications and C++ is still by far my favourite
| language.
|
| It is sad that it is still haunted by prejudice due to pre-C++11
| era but modern C++ is easy to learn and use, and I recommend
| every programmer should give it a try.
| pjmlp wrote:
| The problem is that many keep teaching C++ with code that a C
| compiler won't have any issues with.
|
| That is why Bjarne keeps doing those advocacy talks about best
| practices.
| ModernMech wrote:
| The real problem as I see it is that people think the path to
| safe C++ is to tell everyone "you're holding it wrong" (just
| use modern C++), when it fact being able to hold it wrong is
| regarded as a feature (C++ maintains backward compatibility)
| by the C++ community.
| pjmlp wrote:
| By C expats on C++ country.
| mk89 wrote:
| Related to this, maybe: an issue I had was also the fact that
| online many of the help pages are really outdated.
|
| I can't forget an old accepted "much voted" answer I saw on
| stackoverflow which claimed that raw pointers should be
| owning resources, because that's how the language always did.
|
| I think the answer was dated like 2008 or so, can't find the
| reference anymore. That's when I started to pay a lot more
| attention to the published date whenever I search for help
| and I stumble upon a very old article. If only we could get
| rid of old resources written before maybe 2018-2019 and only
| select those that are still "modern", that'd be already a
| great step forward.
|
| Luckily we have this now [0].
|
| They should invest more in tools like the GSL extension at
| least as a clang warning which really helps, and things like
| that. That's how I believe Java was also able to modernize.
| You can write pretty crappy Java too, but tools like findBugs
| or checkstyle do help, so why not!
|
| [0]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidel
| ines...
| pjmlp wrote:
| That is what using VC++ with integrated support for Core
| Guidelines feels like, naturally that is a minority.
|
| https://learn.microsoft.com/en-us/events/pure-virtual-
| cpp-20...
| mk89 wrote:
| Yeah, I kind of envy that.
|
| Although with Clang-tidy I sometimes see GSL warnings:
| https://clang.llvm.org/extra/clang-tidy/ which is pretty
| cool - I wonder how up-to-date that is compared to the
| GSL extension.
|
| The more you invest in this kind of automated tools, the
| earlier you catch such bugs. Sure, sometimes it's "false
| positives, I know what I am doing", but you cut maybe a
| good > 90% of crap that comes from just writing old-style
| code.
| threatripper wrote:
| In Firefox the code text is only readable in dark mode. In Light
| mode it's dark grey on black with a bright page around it.
| photochemsyn wrote:
| Nice educational resource. Things like this help a lot relative
| to cppreference which often assumes the reader knows many things
| already. For example:
|
| https://cppbyexample.com/what_is_unique_ptr.html
|
| https://en.cppreference.com/w/cpp/memory/unique_ptr
|
| The former spells out the rationale for the design - such as why
| you might need get or why make_unique is better than new, and why
| copies are forbidden but moves are allowed - that the official
| reference sort of assumes the reader already understands.
| MauranKilom wrote:
| I like it. It uses uncomplicated language, doesn't try to
| frontload you with the complexity beneath, and shows clean and
| well-principled code (e.g. no `using namespace std;` - they say
| that all code snippets compile).
|
| And I say this as someone who gets a kick out of template
| metaprogramming.
|
| Yes, you will commit atrocities if you try to learn C++ from
| _just_ this resource. It is very much a nice facade around the
| bottomless pit that is C++. But in terms of getting someone
| started on their first small C++ projects, this is extremely to-
| the-point, and infinitely better than requiring people to dig
| through "how do I read a file" StackOverflow answers or
| needlessly elaborate articles that show terrible code "for the
| sake of exposition".
|
| It might go against the intent of the site, but some kind of
| notice like "C++ is big and has _many_ sharp edges, so you should
| eventually look to curate your understanding beyond this site "
| would round it out.
| exisvr wrote:
| Cool site! I rarely use C++ now, but I still miss C++ from time
| to time!
| arberx wrote:
| As my first language, I've yet to experience another language
| that genuinely lets me be as creative as C++.
|
| There are hundreds of ways to implement and optimize similar
| functionality that I feel like an artist writing in it. This, of
| course, comes with many downsides.
| a3w wrote:
| How do you fell about the pitfalls, like "if you inherit from a
| class, make sure the base destructor is virtual, or you just
| added a memory leak"
|
| Some books on C++ teach you those, but I give up very early on
| learning languages with non-obvious expectations that offers
| few safeguards.
| tejohnso wrote:
| You'd want to read more than one book. And in my opinion you
| also need to digest the C++ Core guidelines and also use
| something like clang-tidy with high sensitivity, and when
| issues are flagged go dig into the details.
|
| But then you realize it's just all too much, and you're
| looking for something less complex again.
|
| I wonder how useful a C++ that I could understand in its
| entirety would be. But I don't understand english in its
| entirety either. I use what I know and get by just fine.
| rramadass wrote:
| That is because C++ is not taught properly. It is not just a
| collection of syntactical features but a multi-paradigm
| language (i.e. supporting Procedural, Object-Oriented,
| Generic and Compile-time) where a feature is best suited to a
| particular paradigm and can also be used to express different
| concepts. Once you grasp this, things become quite clear and
| you _understand how to design in C++._
|
| To take your example; the same C++ "class" syntax can be used
| to express different concepts;
|
| a) A user-defined value type eg. ComplexNumber. Therefore the
| dtor need not be virtual since the class is not designed for
| inheritance.
|
| b) A pure interface used for "Interface Inheritance" i.e. all
| methods are "pure virtual". Therefore you need a pure virtual
| dtor. Java has the "Interface" keyword for this.
|
| c) A class designed for a type hierarchy used for
| "Implementation Inheritance". Therefore you need a virtual
| dtor.
|
| d) A class can also be used as a simple namespace eg. all
| static members; not designed for inheritance and thus no dtor
| needed.
| bogomipz wrote:
| >"That is because C++ is not taught properly. It is not
| just a collection of syntactical features but a multi-
| paradigm language (i.e. supporting Procedural, Object-
| Oriented, Generic and Compile-time) where a feature is best
| suited to a particular paradigm and can also be used to
| express different concepts. Once you grasp this, things
| become quite clear and you understand how to design in
| C++."
|
| Might you or someone else recommend a resource that does
| explain which features are suited for each the programming
| paradigms C++ support? Is there a modern resource that does
| teach it correctly like this? Knowing what features are
| relevant to your paradigm seems like a good way to approach
| learning C++.
| Chabsff wrote:
| That's not even particularly good advice, which just goes to
| show how subtle the pitfalls are. The rule really should be
| "If it is at all possible to delete instances from a pointer
| to the base class, then you need a virtual destructor". The
| overhead of adding a virtual destructor to a base class with
| no other virtual functions is far from negligible in many
| cases, so the distinction is meaningful (though modern
| guidance tends discourage non-polymorphic inheritance in the
| first place anyways).
|
| The same thing goes for the good-old "Do not use raw
| pointers." The rule is actually: "Do not use raw pointers
| with implicit ownership semantics attached to them."
| nyanpasu64 wrote:
| In retrospect I wish C++ used fat pointers rather than
| inheritance for virtual dispatch, like Rust but where
| interfaces/traits can have fields (Rust traits don't have
| fields and are less powerful than C++ base classes). This
| prevents accidentally overriding a base class method (eg.
| QWidget) by declaring a subclass method of the same name,
| eliminates the need to add a vtable pointer to object
| instances which you never cast to an interface pointer, and
| eliminates the need to juggle pointer offsets when
| performing multiple inheritance method calls, which can
| cause UB when performing C-style pointer casts and makes
| decompiling the code a nightmare (possibly fields in traits
| will add this requirement again, I'm not sure).
| ncmncm wrote:
| Inheritance is a specialist technique, use of virtual members
| moreso. Most destructors in modern C++ are left to the
| compiler to generate.
|
| It has been years since I last coded a virtual destructor.
| kazinator wrote:
| Speaking of inheritance, how do you feel about this not
| requiring any diagnostics. It produces a weird result without
| containing any cast notation to subvert the type system.
| $ g++ -Wall -W -Wextra deriv.cc -o deriv $ ./deriv
| 1.08654e-10 $ cat deriv.cc #include <cstdio>
| struct Base { public: double y; Base()
| : y(1.0) {} }; struct Derived : public Base
| { public: int a, b; Derived() :
| a(0x3DDDDDDD), b(0x3DDDDDDD) {} }; int
| main() { Base *b = new Derived[5];
| b++; std::printf("%g\n", b->y); }
| jahnu wrote:
| For me this is the least of c++'s problems. Today I
| wouldn't let that past a review as it should be using a
| std::array. If a c++ dev has a reason to drop down to this
| unsafe code they should know what the consequences are.
| [deleted]
| kazinator wrote:
| There are hundreds of ways to do something, each one more
| importunely verbose and loaded with extraneous syntax than the
| next.
| Chabsff wrote:
| And this half of my main beef with the language. To be clear, I
| absolutely agree that this aspect of it is wonderful, but it is
| a double-edged sword, and the edge pointing at the programmer's
| face is very sharp.
|
| The second half of that beef is that most C++ learning journeys
| bring the learner up to the point of creativity without
| addressing concepts like Strict Aliasing which are not useful
| until you start getting "creative". That's big a problem
| because code containing strict aliasing violations (and/or any
| of a myriad of other UB) is often fundamentally broken while
| giving the illusion of behaving as intended.
| synergy20 wrote:
| or use -fno-strict-aliasing and profile the code to lift it
| for bottleneck code carefully? linux kernel does not allow
| strict-aliasing for example. but I agree yes all c and c++
| course should teach strict aliasing.
|
| in modern c++, also teach RAII and unique_ptr, combined they
| can eliminate so many memory safety problems.
| Chabsff wrote:
| C++ without strict aliasing is not C++ anymore.
| Furthermore, that was just an example. There are other such
| concepts, such as the illegality of accessing memory as
| anything else than raw bytes or the type of the object that
| resides there (which also applies to union fields). Another
| one would be the fact that signed integer overflow is UB.
|
| C++ is so tightly bound to memory layouts that once you
| start getting a solid mental model of what's going on, it's
| _really_ easy to come up with legitimately neat and
| creative ideas that work very well and fast on a test bench
| environment without any complaint from modern compilers,
| but are fundamentally broken. I feel we do not do a good
| job at equipping up-and-coming programmers so that they can
| benefit from that mental model without writing code that
| only works out of sheer luck.
|
| In the extreme, you can write code that does stuff like
| dynamically retype an object by swapping out its vtable
| when vtables are not even thing as far as the language is
| concerned. It's _astounding_ what it sometimes feels like
| you are capable of doing in C++.
| kazinator wrote:
| > _C++ without strict aliasing is not C++ anymore_
|
| That is completely false.
|
| Firstly, a C++ implementation that doesn't optimize based
| on no aliasing assumptions can be entirely conforming: it
| can handle all correct, portable programs in the required
| way.
|
| Secondly, the handling for programs which do type punning
| doesn't make it not C++ anymore; just a dialect. Programs
| in that dialect are C++, just not ISO C++.
|
| Every implementation of a standardized language is a
| dialect of that language; the standard just explains what
| is the common dialect (theoretically) supported by all of
| them.
|
| In fact it's common for C and C++ compilers to recognize
| their own dialect by default.
| arcticbull wrote:
| > That is completely false.
|
| I suppose but only because C++ is everything and nothing.
| C++ compilers are borderline self aware because the spec
| is 'write literally whatever you want'. Skynet was
| obviously a C++ compiler ;)
| kazinator wrote:
| The meaning of punning memory is obvious if you
| understand the implementation-specific representations
| being used. E.g. if you understand what a 64 bit double
| looks like and what a 64 bit integer looks like, then it
| makes sense when you look at the memory of one through
| the type of the other. The C or C++ program to it has
| only two rationally defensible meanings: "undefined
| behavior" (ISO C or C++ interpretation, allowing certain
| optimizations, or run-time diagnosis of a type mismatch
| or whatever) or else "do the obvious thing and access the
| bits like the code says". What the code is asking for can
| certainly be be framed in terms of concepts in the
| standard. Just what the code is obviously requesting is
| not granted by any requirements in the standard. The idea
| that by asking for it, it's not a C++ program any more is
| silly.
|
| There is no standardized programming language that
| doesn't have vendor specific extensions comprising a
| local dialect.
| synergy20 wrote:
| I understand compiler likes strict aliasing for
| performance optimizations, use it carefully but _only_ at
| bottleneck-ed areas seems like a good trade-off between
| safety and performance, why without-it is no c++ anymore?
| why do I need do pointer aliasing randomly?
| Chabsff wrote:
| Strict aliasing is what prevents compilers from having to
| sprinkle Load-Hit-Stores all over the place. This is not
| a marginal performance difference, and doubly-so for CPUs
| with deep execution pipelines. It also has _massive_
| code-reordering implications.
|
| In any case, Strict Aliasing is not a flippant rule that
| compilers like to apply. It's a formal component of the
| ISO standard that C++ is.
|
| You can chose to make a deal with a compiler (via a flag)
| to compile otherwise non-compliant code in a consistent
| way, but that does not change the fact that the code is
| non-compliant.
| kazinator wrote:
| There are ways of coding coding in C which makes those
| optimizations unnecessary.
|
| The basic idea is: don't load your block of code with
| lots of pointer dereferences. Load the values you need
| into local variables. Don't proliferate common
| expressions which dereference the same pointer to get at
| the same value. Consolidate the assignments through
| pointers. Don't do this in three places: (*ptr)++. Have
| that value in a local variable var, and do var++ in three
| places, then assign it *ptr = var.
|
| Even without no-strict aliasing, a compiler can still
| assume that local variables whose addresses are not taken
| are not the targets of any pointers.
|
| In C (99 or later), you have _restrict_ also. _restrict_
| is independent of strict aliasing, because it 's not
| based on type.
|
| Furthermore, speaking of restrict, aliasing between _like
| typed_ objects matters for optimization. It 's good and
| well to optimize based on the idea that a _double *
| cannot be aiming at an object whose declared type is_
| long _. But it 's insufficient, because code that is
| manipulating _double * pointers is likely working with
| objects of type _double_ which could be the targets of
| those pointers. So without some combination of tight
| coding and possibly using restrict, you will end up with
| those load-hit-stores in all sorts of code.
|
| This code for removing from a linked list:
| node->prev->next = node->next; node->next->prev =
| node->prev;
|
| still isn't as good as this: node *next
| = node->next; node *prev = node->prev;
| next->prev = prev; prev->next = next;
|
| The problem is that the common expressions can't be
| eliminated based on aliasing, and the aliasing is between
| like types, so strict aliasing doesn't help.
|
| With gcc (x86) I get: movl
| (%eax), %edx movl 4(%eax), %ecx
| movl %ecx, 4(%edx) movl 4(%eax), %eax
| movl %eax, (%eax)
|
| versus: movl (%eax), %edx
| movl 4(%eax), %eax movl %eax, 4(%edx)
| movl %edx, (%eax)
|
| We shaved off an instruction through tighter coding, and
| IMHO (in this case) improved the readability also.
|
| That was gcc 7 on Ubuntu. The result is exactly the same
| like what I saw under gcc 2.7.x a quarter century ago.
|
| How about gcc 11, x86-64? I should probably be using
| godbolt, but anyway, also five instructions down to four:
| movq (%rdi), %rax movq 8(%rdi), %rdx
| movq %rdx, 8(%rax) movq 8(%rdi), %rax
| movq %rax, (%rax)
|
| vs: movq 8(%rdi), %rax
| movq (%rdi), %rdx movq %rax, 8(%rdx)
| movq %rdx, (%rax)
|
| (I think in this particular case the compiler could do a
| better job because even if the assignment
| "node->prev->next = node->next" clobbers the value of
| "node->next" due to the nodes being aliases, the
| assignment can only clobber it with the value that
| node->next already has! The compiler doesn't analyze it
| that far though.)
|
| C was designed from the start as a language which the
| programmer does the optimizing, and regardless of the
| advancements in compilers, that has not been entirely
| eliminated.
|
| How you write C still makes a difference, even at the
| microscopic level of individual statements and
| expressions, not just the level of overall program
| organization and use of algorithms.
|
| If you write tight code, you can turn off strict aliasing
| optimizations globally and it won't matter. But you don't
| have to do that globally. You may be able to confine your
| type punning hack in its own source file, and just turn
| it off for that file. (Or may be even on a finer
| granularity if you have such compiler support.)
| stoeckley wrote:
| I remember once telling a friend of mine, after I'd spent
| several years writing Clojure full-time, that upon
| getting back into writing C++, the feeling was like
| "sculpting with electricity." There is a strange sense of
| power you feel from harnessing the language in a creative
| way, unlike any other language I've used.
| kazinator wrote:
| Did he mean with rubber gloves and insulated mat, or
| without?
| [deleted]
| rramadass wrote:
| https://blog.sigplan.org/2021/11/18/undefined-behavior-
| deser...
| Chabsff wrote:
| Just in case you posted this as a counterpoint to what I'm
| saying...
|
| This blog effectively agrees with my position: Undefined
| Behavior is just "Stuff the compiler is allowed to assume
| never happens". And C++'s set of Undefined Behaviour is a
| fundamental part of what makes it valuable.
|
| The issue I have is not with them, but rather with the fact
| that it's too easy to become competent, if not talented,
| way past the point where one should take them into account
| without having to even know of their existence.
| volsa_ wrote:
| As someone who tried learning C++ a few years ago this is
| (personally) my biggest gripe with the language and this gif[0]
| perfectly sums it up. Gave up and started learning Rust
| instead, which I'm very happy about in hindsight.
|
| [0] https://twitter.com/timur_audio/status/1004017362381795329
| ncmncm wrote:
| Fortunately, those can almost all be ignored almost all the
| time.
|
| Rust will seem fine until you are writing a library and find
| no way to express what would make the library nicer to use;
| or you find using some library awkward and error-prone.
| Almost every C++ feature is designed to enable delivering
| more powerful libraries, and they compound.
|
| So, in C++ you as library writer are empowered to make the
| use of your library correct by construction: what compiles is
| safe and correct. Rust makes the compiler responsible for
| _memory_ safety, but offers much less to make using your
| library pleasant and foolproof.
| volsa_ wrote:
| > but offers much less to make using your library pleasant
| and foolproof
|
| Not my experience so far, I might go as far and say it
| makes it more foolproof because when writing your library
| you have the option to return an `Option` or `Result` enum.
| ncmncm wrote:
| Option and Result types are as easily coded in C++.
|
| The former is in the Standard C++ library. The latter
| will be in the next, but anyway the one in Boost has
| worked fine forever.
|
| Throwing, instead, is a choice unavailable to Rust
| coders, so you often have no alternative but to return
| these more complicated things that users are then obliged
| to unpack. A standard macro makes that easier, and is
| semantically equivalent to throwing, but imposes
| substantial overhead on successful calls.
| Rusky wrote:
| C++'s option and result types are much larger, uglier,
| and harder to use correctly than Rust's. The shift from
| throwing to returning a Result is not really an increase
| in complexity- closer to a reshuffling of syntax.
|
| But that's not really all that relevant either, because
| comparing languages at this level of detail misses the
| forest for the trees. An interesting comparison takes a
| step back and compares which problems the languages (try
| to) solve. Often something that appears to be a clear win
| for one or the other turns out to be a non-issue.
| arinlen wrote:
| > _C++ 's option and result types are much larger,
| uglier, and harder to use correctly than Rust's._
|
| What's your rationale for claiming in a swiping
| generalization that implementing a data type, regardless
| of all options or approaches and design, has no other
| option than doing everything wrong?
| Rusky wrote:
| I mean, have you looked at them?
|
| C++'s standard library optional type is a tagged union
| implemented from scratch, with a dizzying array of
| template metaprogramming to meet the standard's
| requirements- see e.g. Microsoft's here: https://github.c
| om/microsoft/STL/blob/main/stl/inc/optional#.... This
| isn't a criticism of the team behind this code, it's just
| what it takes to do this in C++.
|
| Rust gets most of that functionality from the language
| instead, in a much cleaner way. Sum types are built in,
| value categories and move semantics are handled
| automatically, there is little-to-no metaprogramming, and
| most of the API is just simple convenience combinators
| with obvious implementations: https://github.com/rust-
| lang/rust/blob/master/library/core/s...
|
| If nothing else, this is a clear counterexample to the
| claim that "Option and Result types are as easily coded
| in C++."
| ncmncm wrote:
| > _it 's just what it takes to do this in C++_
|
| False.
| LegionMammal978 wrote:
| Do you have any examples of how std::optional could be
| implemented more simply?
| arinlen wrote:
| > _I mean, have you looked at them?_
|
| Last time I looked at Rust's std::Result, it's
| implemented as a tagged union.
|
| Most of C++'s implementations of a Result data type are
| implemented as tagged unions as well.
|
| What's your point?
|
| > _This isn 't a criticism of the team behind this code,
| it's just what it takes to do this in C++._
|
| The only conceivable argument you can possibly make is
| argue that Rust might support tagged unions as language
| primitives, but that would be totally pointless as Result
| types are relevant for the interfaces and higher level
| abstraction they provide, not your personal opinion of
| how hard someone else had to work to implement them.
|
| I've developed Result and Either types in a few
| languages, including C++, and the only hard thing about
| C++ is doing the usual homework to handle
| lvalur/revalue/revalue well.
| ncmncm wrote:
| The substantial performance overhead, in Rust, of code to
| handle those types is unavoidable, even where source-
| level inconvenience has been minimized.
|
| Overhead is imposed all up and down the call chain, every
| time through. Seems pretty relevant to me.
| mathstuf wrote:
| The fact that `std::optional<T&>` is verbotten makes them
| quite a bit more useless. The Boost one is _better_
| because it doesn 't have this misguided limitation. It's
| really quite a sad story and a loss to all of C++ that it
| is this way (and not for lack of trying on ThePhD's
| part).
|
| > no alternative but to return these more complicated
| things that users are then obliged to unpack
|
| Yes, thank you. It is much better this way. I think
| "substantial overhead" needs to be backed up with some
| numbers here because setting up exception landing pads is
| certainly not free.
| mathstuf wrote:
| > So, in C++ you as library writer are empowered to make
| the use of your library correct by construction: what
| compiles is safe and correct
|
| Empowered? Sure. But it seems no one likes using that power
| for long stretches of time. Rust gives the same power and
| it gets used far more usefully IME.
|
| > Almost every C++ feature is designed to enable delivering
| more powerful libraries, and they compound.
|
| Well, we can take `std::variant`, `std::optional`, and
| `std::expected` out of that pool because the committee
| hamstrung them from their better alternatives that already
| existed in Boost for silly, misguided reasons.
|
| > Rust makes the compiler responsible for memory safety,
| but offers much less to make using your library pleasant
| and foolproof.
|
| C++ libraries have, historically IME, been far more likely
| to ask you to juggle live grenades while dancing in a
| minefield than Rust libraries and APIs have.
| oconnor663 wrote:
| I think Rust's combination of data-bearing enums and
| destructive move semantics goes a really long way towards
| letting library authors express their invariants through
| the type system. And that's in addition to the borrow
| checker and mutable aliasing rules. The mutable aliasing
| rules in particular are often kind of annoying for callers,
| but they're a godsend for API authors, because they allow
| for methods like Mutex::get_mut that don't even need to
| lock the Mutex, in safe code!
| alfiedotwtf wrote:
| Same here... I got through Stroustrup and thought I'm not
| smart enough to write this error free. Been happy with Rust
| ever since.
| cyber_kinetist wrote:
| It's all fun and games until you find the need to unsafe
| Rust, which opens up a bunch of eldritch monstrosities that
| are sometimes even harder to tame than C++.
|
| The happiness people get from Rust was achieved by the
| incredibly hard work of library developers who had to deal
| with all sorts of complex semantics under the hood to make
| safe Rust safe. The knowledge gap between library user and
| library writer is even worse than C++, where most people do
| not feel comfortable enough to actually write low-level
| libraries (custom data structures, bindings from C,
| optimized routines) in Rust.
|
| (At least PL people are inventing things like stacked
| borrows to make writing unsafe Rust easier... but it's
| still not easy.)
| unrealhoang wrote:
| on the other hand, that makes Rust's learning curve way
| way more gradual than C++. An intermediate programmer
| with 3 months of Rust experience can reliably and
| confidently cobble up the libraries together to
| contribute to the project. Whereas such programmer will
| be a heavy burden (for other seasoned devs to
| guide/review/feedback) in a C++ project.
|
| Also, building low-level libraries that work correctly,
| efficiently, relatively-safely in C++ is NOT a simple
| feat, and requires years of experience (on API design).
| With unsafe Rust you can just fuzz/brute force out the
| unsoundness with the safe API.
| spoiler wrote:
| > It's all fun and games until you find the need to
| unsafe Rust, which opens up a bunch of eldritch
| monstrosities that are sometimes even harder to tame than
| C++
|
| Lol what? Unsafe is literally the only "mode" in C++. I'm
| not trying to shill Rust, but this is not true, and I
| don't know where you've read that opinion. Unsafe Rust is
| just Rust with the ability to use "C++ style" pointers.
|
| > The happiness people get from Rust was achieved by the
| incredibly hard work of library developers
|
| I'll give you that writing Rust libraries is harder, but
| that's true for any language. Even C++. Do Rust
| developers go the extra mile to make libraries ergonomic
| and have nice APIs? Yes! But that's not really a
| "problem" with Rust, it's something Rust enables, and now
| the community expects. C++ libraries in my experience
| tend to be a very bare minimum, and to use some of them
| it requires hundreds of lines of set up code. In cases
| where Rust libs require that much set up code, the
| authors go the extra mile to create macros or additional
| succinct APIs. So, yeah, their job is harder because they
| are held to a higher standard than C++ libraries, if
| anything.
|
| Also, most of the effort with authoring Rust libraries is
| writing documentation, which is practically a
| requirement, whereas with most C++ libs (even some
| sections of boost!) you practically weep tears of joy
| when you see five lines written above a one class in a
| sea of classes.
|
| > who had to deal with all sorts of complex semantics
| under the hood to make safe Rust safe. The knowledge gap
| between library user and library writer is even worse
| than C++, where most people do not feel comfortable
| enough to actually write low-level libraries (custom data
| structures, bindings from C, optimized routines) in Rust.
|
| Sorry to be so blunt and call you out, but this is just
| so devoid of any sensible thought.
|
| Most people don't feel comfortable writing low level
| libraries. Period. Regardless of language. For every
| library author, there's dozens of not hundreds of non-
| libray developers. Hell, most developers don't even
| contribute anything to open source in general, but just
| consume it.
|
| So pretending C++ is this magical fairytale land where
| everyone produces libraries with the flick of a wrist is
| just bullshit.
| boppo1 wrote:
| Which Stoustrup, principles or the c++ language tome?
| forgotpwd16 wrote:
| >There are hundreds of ways to implement and optimize similar
| functionality that I feel like an artist writing in it.
|
| Perl? Can even write poetry in it.
| https://docstore.mik.ua/orelly/perl/prog3/ch27_02.htm
| avg_dev wrote:
| that is amazing
| ncmncm wrote:
| "If new true friend not protected for explicit private union,
| break case and try using this."
| bstamour wrote:
| ... I think the perl code actually compiles (err, runs)
| though. :-)
| medo-bear wrote:
| > As my first language, I've yet to experience another language
| that genuinely lets me be as creative as C++
|
| common lisp is cpp's way more talented brother that got
| addicted to lsd and became a hippy
| latenightcoding wrote:
| don't worry Perl will let you be 100 times more creative
| mattlondon wrote:
| Try modern pure JavaScript. It's like floating through air. An
| absolute joy to code in.
|
| Of course if you want to talk about performance and stuff then
| JavaScript is not comparable, but that is not the point
| layer8 wrote:
| The lack of static typing will be a non-starter for many.
| arberx wrote:
| The "official" reference if anyone is interested:
| https://en.cppreference.com/w/
| anta40 wrote:
| And for those who want offline copy:
| https://en.cppreference.com/w/Cppreference:Archives
| ncmncm wrote:
| "Official", quote, alludes to very active curation by
| participants in the standardization process, with example code
| frequently updated to reflect changing best practice.
|
| Recognized best practice changes with both experience and with
| newly implemented language features. New features are proposed,
| and some standardized, specifically because they enable better
| ways of coding. So, best practice may change markedly with each
| new Standard.
|
| Generally, _the newest way to do something is usually best_ ,
| for exactly that reason. (A common misconception has one
| sticking with older language features for better code. The
| _reductio ad absurdum_ of this would prefer the C subset.) This
| does not oblige you to use every feature in every program;
| e.g., _std::shared_ptr_ has sharply limited value. And, the
| absolutely newest features may not be very portable yet.
|
| Sometimes more field experience with a feature and its
| interaction with others leads to changes to best practice. This
| should be expected particularly in use of concepts and
| asynchronous facilities.
|
| As an example of change, the present universal preference for
| "std::" vs "using" took a long time to gel because writers (of
| articles, slides, textbooks) begrudged the extra space it took
| on their page.
|
| Examples found on cppreference may usually be relied upon to
| produce sound results and to steer well clear of both risky
| usage and bad performance.
| planede wrote:
| Definitely the best C++ reference. It's not official in the
| sense that it is not the authoritative standard text itself,
| but it is very precise and complete.
| qsort wrote:
| Definitely THE website to bookmark if you're interested in C++
| at all.
|
| Notice that due to SEO fuckery, your first search result might
| be cplusplus.com, which is not the same and not as good.
| cppreference.com is where it's at.
| jjtheblunt wrote:
| I must be a Scheme "snot", because the definition of "lambda" in
| C++ (and other languages) is not semantically what lambda in
| Scheme is.
|
| (There's a different definition of closure than in Scheme, with
| different implications as a result.)
| ncmncm wrote:
| C++ lambda is particularly adapted to the needs of C++, and C++
| programmers. It would be very surprising if it matched any
| Lisp's. Lisps differ from one another, too.
| stall84 wrote:
| this is great
| hemloc_io wrote:
| Is there something like this for Java?
|
| I feel like the more popular languages get the more people write
| blogspam that gets in the way.
|
| E.g. If you search "libs for rust" you get https://lib.rs/ but
| try doing "libs for java" and uh, it's not great.
| saghm wrote:
| I think that probably has more to do with the fact that Rust
| libraries basically all come from the same place, since there's
| been centralized package management since the very early days.
| It's a lot harder to support something like that after the fact
| than designing for it in advance; new languages like Rust have
| an advantage in that regard.
| [deleted]
| planede wrote:
| This looks like a nice start for a good guide. Some hierarchy for
| the examples would be nice, instead of an alphabetically sorted
| list. There are some minor inaccuracies here and there, but
| overall looks alright.
| ComplexSystems wrote:
| I'm surprised this comments section isn't made up of people
| talking about how we should never use C++ again and only use Rust
| from now on.
| ncmncm wrote:
| That only happens in specially marked Rust-advocacy posts.
|
| More people pick up C++ to use professionally in any given week
| than the total population of working Rust coders. Rust is
| practically invisible outside hipster media.
| tialaramex wrote:
| > More people pick up C++ to use professionally in any given
| week than the total population of working Rust coders
|
| Nathan here also believes that despite this, firms including
| Mozilla, Google and Microsoft haven't been able to hire any
| _engineers_ who can write C++ properly and so that 's the
| root cause of their problems.
|
| I think that if so very many people "pick up C++ to use
| professionally" in each week and yet apparently none of them
| are any good at it, we should consider that the problem might
| not be with the people at all.
| ncmncm wrote:
| [flagged]
|
| Do not put words in my mouth. Do not make shit up. Go away.
| agomez314 wrote:
| this page reminds me of https://learnxinyminutes.com/
| MatthiasPortzel wrote:
| Learn X in Y minutes in my go-to when I'm writing code in a new
| language. Just the examples of syntax of a language are very
| useful and surprisingly hard to come by in formal
| documentation.
___________________________________________________________________
(page generated 2022-09-22 23:02 UTC)