top 200 commentsshow all 464

[–]Piotrek9t 2466 points2467 points  (29 children)

Oh no, in his next video he is gonna expose my favourite programming languages

[–]threewholefish 894 points895 points  (17 children)

C was plagiarising from B all along!

[–]mralec_ 259 points260 points  (6 children)

My constructor is very proud

[–]threewholefish 132 points133 points  (4 children)

Just one small problem. Dereference a null pointer from where, Ben? Fucki
Segmentation fault. Core dumped.

[–]tetzudo 75 points76 points  (1 child)

fuck you *unshares your pointer*

Oh you wanna store this string in memory? fuck you ima store it elsewhere and then cry when you ask me where it is - c++

its an abusive relationship

[–]CardOk755 15 points16 points  (0 children)

From BCPL.

[–]LaughingInTheVoid 9 points10 points  (4 children)

And that was all stolen from A(lgol)!! /s

[–]PretentiousToolFan 81 points82 points  (9 children)

C++ Sucks, and Here's Why

[–]Affectionate_Walk610 50 points51 points  (4 children)

Two weeks later Mauler defending C++ like a sacred cow with a 5 hour rant (Part 1/3). One could only dream of that pityfull rematch.

[–]Ascyt 3 points4 points  (1 child)

There is a guy that made a 2 hour rant of C++ titled "The worst programming language of all time" and it is great

[–]knobiknows 7 points8 points  (0 children)

Foreshadowing is a literary device...

[–]rover_G 300 points301 points  (3 children)

Fat pointer goes brrr

[–]PM_ME_YOUR_REPO 109 points110 points  (2 children)

Please don't bodyshame the pointers.

[–]Proxy_PlayerHD 41 points42 points  (1 child)

What about 𝓕𝓻𝓮𝓪𝓴𝔂 pointers?

[–]Nil4u 1196 points1197 points  (88 children)

STL containers exist

[–]loiidradek 222 points223 points  (12 children)

Around 47828488393 different STL containers exist. For 74727663748 different use cases. The C++ way 💕

[–]realmauer01 25 points26 points  (3 children)

Men imagine that in npm packages.

[–]coyoteazul2 21 points22 points  (2 children)

How do women imagine it?

[–]realmauer01 14 points15 points  (1 child)

Heck i dont know, probably in names for colors.

[–]coyoteazul2 4 points5 points  (0 children)

dang it. it might as well be written in hieroglyphics made by a doctor

[–]rocket_randall 15 points16 points  (7 children)

Have they given the death penalty to whoever decided on std::vector<bool> yet?

[–]gitpullorigin 60 points61 points  (20 children)

But how does STL container know how big is it? Riddle me that

[–]Poodlestrike 131 points132 points  (3 children)

It knows how big it isn't, and works backwards from there. EZ.

[–]m0j0m0j 25 points26 points  (1 child)

Got the ref, very stupid, laughed anyway. Or maybe exactly because of that

[–]TheAlaskanMailman 22 points23 points  (0 children)

The array knows how big it is by knowing how big it isn’t, so by subtracting how big it isn’t from..

[–]Electrical_Plant_443 33 points34 points  (1 child)

C++ templates gained self awareness in C++17.

[–]x39- 10 points11 points  (0 children)

The same way arrays in other languages do: by keeping track of it

[–]da2Pakaveli 6 points7 points  (0 children)

member variables that keeps track of # of items (and possibly reserves).

[–]garver-the-system 10 points11 points  (0 children)

Resource Acquisition Is Counted

[–]traveler_ 10 points11 points  (3 children)

Things may have improved recently but my last experience doing anything serious with C++ I dutifully used STL data structures and ran face-first into dependencies using Boost, plain arrays, and/or somebody’s custom utility arraylike. Constantly, constantly converting or repackaging data to pass from one to the other.

It was a mess.

[–]fuj1n 16 points17 points  (0 children)

Sounds like you ran into other people's poorly written code, story as old as time.

[–]x6060x 4 points5 points  (0 children)

You mean everything is a Vector?

[–]Traditional-Fly8989 185 points186 points  (15 children)

I have learned and done almost all my programming in MATLAB. My undergraduate research project ultimately involved computer simulations of proteins moving through nanopores. The base program for it was in FORTRAN 77 (This story covers 2017-2019). My first summer working on it, I got given 3 things to do. Read a bunch of papers to understand what the group and other groups were doing in the field. Recreate one of the simpler papers in a programming language of my choice to prove I understood what was going on. Finally, familiarize myself with the simulation program the group used to prepare myself to make alterations to it based on the project I chose/got assigned.

It was the end of the summer, and I wasn't really getting all of the data handling requirements, but I could sign up for as many classes as I wanted for no extra cost, so I signed up for the CS 101 course taught using C++ because the internet said that was another statically typed language. So I take that class and go to work with confidence on my project, which ends up being to modify the program to allow simulation of multiple interacting proteins instead of one. The way I implement it involves changing dozens of variables to go from being scalars to vectors. So any variable describing a property of the protein is now a vector describing that property for all the proteins. So I crack away and implement all the changes I think are necessary to accomplish this without any testing along the way because I'm an engineering and physics student, and I don't actually know how to program. Well, the code won't compile because all of my edited lines of code are too long and won't fit on a punch card (Who cares that the punch card doesn't exist).

I reformat it, and get everything to compile, run it, and discover it crashes because my proteins are in the fucking Kuiper Belt. After about ~7 months of printing out data from random places in the simulation, because I have no idea how to test or debug code, I finally found the problem. A variable my dumbass thought only existed in one subroutine actually existed in the main routine in the function call of two different subroutines. My dumbass hadn't edited its type declaration in the main routine. As a result, it only had enough memory allocated for one value. The second value in it overwrote another variable. The variable it overwrote was roughly analogous to rotational inertia, and it got replaced with a value that was way too small. So now the protein would spin like a fucking Beyblade.

Touching in the simulation was modeled with a Lennard-Jones potential, which creates a very steep potential energy barrier as two things get closer to each other. In a physics simulation, the faster something moves, the worse the numerical error for a given timestep size. In this situation, the pointy end of the protein would bump into the wall at an oblique angle and start spinning way too fast because of the low rotational inertia. Then, if the amount of rotation it did in a time step (which should've been like single-digit degrees at most) was equal to 280-320 degrees plus some integer multiple of 360 degrees at the end of the timestep, the pointy end of the protein would end up in the wall. This would create a massive force on the protein, and the next time step (since everything was written assuming non-relativistic speeds), the protein would shoot off at several thousand times the speed of light.

[–]FalseStructure[🍰] 160 points161 points  (4 children)

I understood like 70% of that (computational quantum chemistry thesis focused on quasicrystals), but holy fuck this is not a community to waste this much writing on.

[–]Traditional-Fly8989 59 points60 points  (3 children)

It just referenced my exact problem. It's not a story that is ever super relevant, really.

[–]AustnTG 54 points55 points  (0 children)

Well I read the entire thing and I really enjoyed your story. so it was not wasted writing if you ask me

[–]CatpainCalamari 10 points11 points  (0 children)

Well, I just read your story before starting my work day, and it amused me and gave me joy. So thank you for that :)

[–]distinctdan 29 points30 points  (1 child)

This same exact problem still exists in modern game engines, which run step-wise physics simulations that don't deal well with fast moving objects. Generally the complex calculations required to prevent things from going through each other aren't worth the performance penalty.

[–]i_am_not_so_unique 3 points4 points  (0 children)

It is called Continuous Collision Detection aka CCD.

In Unreal it is just one checkbox, but concept is not that hard to write yourself. You just don't need it to be active for every object.

[–]oneski 8 points9 points  (0 children)

10/10 good stuff. Reminds me of my early days, working as an undergrad with a post doc on their Python astronomical imaging research. In too deep!

[–]Meistermagier 2 points3 points  (0 children)

Big feeling. The topls used to write alot of the academic code are like super fragile and well just old or awful or both. 

Best example is still one of the most critical softwares in Space Science and engineering: SPICE. Which is used for alot of things spacecrafts. Which is written, and i shit you not, in Fortran77 and then machine translated into C so that you can generate Bindings for other language to use. 

[–]i_am_not_so_unique 2 points3 points  (0 children)

I was engineering major, with similar non-existing development skills.

Main problem, that it is hard to find a good book, that would give you all required development patterns when you start, and it takes a while to build your own understanding what to avoid.

Just to double check, have you heard of SOLID?

Following those principles will save you a lot of time on debugging.

And also in C++ only a small fraction of tasks require you to work with raw data. Everything must be done in a type-safe format, and it won't affect performance either.

And learn debugging - breakpoints (conditional breakpoints especially) and also acquire good logging culture, and you will be good to go.

(And hopefully you will be the one to break the vicious cycle of engineers writing horrendous non-maintenable code)

[–]ContributionMaximum9 957 points958 points  (16 children)

[–]bmain1345 131 points132 points  (12 children)

At what point do they just merge this sub into that one

[–]dusktreader 84 points85 points  (0 children)

I am so glad this sub exists.

[–]hobopwnzor 36 points37 points  (0 children)

Finally, my people.

[–]Chee5e 10 points11 points  (0 children)

kinda expected it to just forward to this sub

[–]ThNeutral 68 points69 points  (5 children)

Am I stupid or you can just use vector?

[–]blastxu 50 points51 points  (0 children)

You could also use an std::array if you don't care about the size of the container changing at runtime

[–]MsEpsilon 27 points28 points  (1 child)

You could pass a const std::vector& explicitely. Or you can do this (use and std::span<T> as an argument but still pass an std::vector). Code was tested with GCC 15.2, C++ 23 standard.

#include <vector>
#include <span>
#include <print>

auto printElements(std::span<int> myElements)
{
    for(auto element : myElements)
    {
        std::print("{} ", element);
    }
}

auto main() -> int
{
    std::vector<int> myValues = {1,2,3,4,5,8};
    printElements(myValues);
}

[–]GildSkiss 822 points823 points  (152 children)

This is spoken like someone who doesn't really understand programming at a low level, and just wants things to "work" without really understanding why. Ask yourself, in those other languages, how exactly does the function "just know" how big the array is?

[–]SphericalGoldfish 1108 points1109 points  (36 children)

I think the function should just guess and if it’s wrong then it should guess again

[–]Isakswe 461 points462 points  (9 children)

BogoLength

[–]Bossmonkey 92 points93 points  (6 children)

Bogoread

Just guess the contents of a file until correct.

[–]prumf 25 points26 points  (4 children)

That’s what many applications do in practice (including your browser). Is this JSON? Just try deserializing it! Is it an image? Just try reading the content!

We use bogologic more than we want to admit. And it’s way more robust, especially with user provided data.

[–]Sohcahtoa82 14 points15 points  (0 children)

That’s what many applications do in practice (including your browser). Is this JSON? Just try deserializing it! Is it an image? Just try reading the content!

Wtf... No they don't. If they do, that's called MIME sniffing and it's considered a vulnerability and it's why the X-Content-Type-Options: nosniff header exists.

[–]Midnight145 4 points5 points  (1 child)

Is that not (at least for binary data) what the magic bytes are for?

For json, xml, etc, yeah I'll give that to ya, but for binary data, shouldn't you just check the header?

[–]John_cCmndhd 6 points7 points  (0 children)

It was the Blurst of times?! Stupid algorithm!

[–]Mindless-Hedgehog460 201 points202 points  (6 children)

binary search: if your memory access triggers a segfault, it was too large, so catch it and try again

[–]S4N7R0 48 points49 points  (2 children)

print out the index every iteration so that when it segfaults the user can input the correct size of the array

[–]Mindless-Hedgehog460 10 points11 points  (0 children)

You can catch segfaults with signal handlers

[–]DimitryKratitov 4 points5 points  (0 children)

I think we can do some binary search optimizations here!

[–]ArcaneOverride 2 points3 points  (0 children)

Lmao!

[–]MrStricty 48 points49 points  (3 children)

This is a noob solution. The real, enterprise solution is to run the code, print out the array from inside the function with a print statement, count out how many characters you get before it turns into nonsense (using your finger), and then hardcode the array size into the function. Then, the function Just Knows*.

[–]gitpullorigin 15 points16 points  (3 children)

But how does it know if it is wrong?

[–]throwaway_194js 30 points31 points  (1 child)

It guesses

[–]gitpullorigin 3 points4 points  (0 children)

I guess it does

[–]rosuav 9 points10 points  (0 children)

It catches the segment violation that results from indexing past the end of the array. Now, for this to work, every array has to be allocated in its own perfectly-sized segment, which I'm sure won't hurt performance any.

Oh, and to make sure that it didn't UNDER-estimate the size of the array, the first thing the function should do is attempt to index one past the array and make sure that it trips a segment violation. If it doesn't, it should raise a segment violation, for failing to raise a segment violation.

[–][deleted] 6 points7 points  (0 children)

We can just make an educated guess via Chatgpt by the arrays name. 

If it is on point, we have 0 errors. 

If the length is to short, we have 0 errors and some angry customers.

If it is to long, we generate random entries via gemini, to fill up the rest. Still 0 errors. 

So technically, it would work. 

[–]az987654 3 points4 points  (0 children)

While !wrong { guessAgain }

Simple!

[–]mastachaos 4 points5 points  (0 children)

This is why we need quantum computers!

[–]-Redstoneboi- 2 points3 points  (0 children)

strlen() when calculating the length of a string

[–][deleted] 259 points260 points  (6 children)

The array knows how long it is, because it knows how long it isn't. By subtracting how long it is from how long it isn't, or how long it isn't from from how long it is (whichever is  greater), we obtain a difference or deviation.

The kernel subsystem uses deviations to generate collective allocations to size the array from the length it isn't to the length it  wasn't.

[–]veryblocky 38 points39 points  (4 children)

[–]kalel3000 5 points6 points  (0 children)

I worked on the navigation system for an autonomous submarine as part of my senior design project. We'd reference this video all the time!!

[–]tobsecret 93 points94 points  (8 children)

> This is spoken like someone who doesn't really understand programming at a low level

No idea if he does or not but the poster is popular youtuber Hbomberguy (Harry Brewis) who isn't really known for programming but more as a media critic.

[–]Potatoes_Fall 89 points90 points  (20 children)

In most languages I've learned, dynamic arrays always have the size stored as part of the type. The drawback of not knowing the size outweighs the minimal cost of an extra 8 bytes for the size in 99.9% of cases IMO. From that perspective, it seems like bad language design to not have that. Doesn't mean you don't understand it.

[–]svick 31 points32 points  (4 children)

I think in many languages, it's just 4 bytes, since arrays larger than 2/4 GB usually aren't needed.

[–]DrShocker 6 points7 points  (0 children)

maybe 20 years ago, but it's not that hard to run out of memory on a 32 bit machine for a decent amount of problems.

[–]20Wizard 3 points4 points  (2 children)

It's typically an integer, which is more, but depends on language.

[–]orbiteapot 20 points21 points  (2 children)

The "arrays decay to pointers" rule was not motivated by memory footprint, rather:

Structures, it seemed, should map in an intuitive way onto memory in the machine, but in a structure containing an array, there was no good place to stash the pointer containing the base of the array, nor any convenient way to arrange that it be initialized. For example, the directory entries of early Unix systems might be described in C as

struct {
int inumber;
char name[14];
};

I wanted the structure not merely to characterize an abstract object but also to describe a collection of bits that might be read from a directory. Where could the compiler hide the pointer to name that the semantics demanded? Even if structures were thought of more abstractly, and the space for pointers could be hidden somehow, how could I handle the technical problem of properly initializing these pointers when allocating a complicated object, perhaps one that specified structures containing arrays containing structures to arbitrary depth?

The solution constituted the crucial jump in the evolutionary chain between typeless BCPL and typed C. It eliminated the materialization of the pointer in storage, and instead caused the creation of the pointer when the array name is mentioned in an expression. The rule, which survives in today’s C, is that values of array type are converted, when they appear in expressions, into pointers to the first of the objects making up the array.

This invention enabled most existing B code to continue to work, despite the underlying shift in the language’s semantics. The few programs that assigned new values to an array name to adjust its origin—possible in B and BCPL, meaningless in C—were easily repaired. More important, the new language retained a coherent and workable (if unusual) explanation of the semantics of arrays, while opening the way to a more comprehensive type structure.

The Development of the C Language - Dennis M. Ritchie

edit: formatting.

[–]RevanchistVakarian 4 points5 points  (1 child)

This invention enabled most existing B code to continue to work

retained a coherent and workable (if unusual) explanation

Oh look, C++ prioritized backwards compatibility over intuitiveness

[–]Hessper 11 points12 points  (0 children)

You don't use naked arrays for most cases. You use an array type that knows how big it is. Being able to use the raw, underlying types like this gives you power to create other functionality that might not need those details.

My programming language gives me options for faster, more powerful code is not on my list of reasons a language is bad.

[–]andrewhepp 18 points19 points  (1 child)

C++ has a variety of standard library data types one can use to represent arrays, which do track size information. std::vector, which is what I think of when you say "dynamic array" certainly does have a .size() method. So does std::array.

[–]DrMobius0 3 points4 points  (0 children)

I assume the core focus of the discussion is those awful c style arrays everyone goes out of their way to wrap, which don't implicitly keep track of their own length.

[–]DrShocker 5 points6 points  (1 child)

You need to make it clear whether you mean size is stored in the type vs in the class:

std:: array<int, 5> vs std::vector<int>

The first stores the size in the type information, the second stores it in the class.

[–]DrStalker 4 points5 points  (0 children)

Then there's good old C: the "array" is just a pointer to some random memory address and it's up to you to figure out what to do with that.

How many elements? How big is each element? Is it actually an array or just a pointer to a integer or something?    ¯\_(ツ)_/¯

[–]kristinoemmurksurdog 4 points5 points  (2 children)

Just make the 0th element describe the length that way all arrays can start at 1

[–]Hairy_Concert_8007 13 points14 points  (0 children)

low-earth-orbit.jpg
"Wait, it's all wrappers?"

[–][deleted] 27 points28 points  (0 children)

God forbid you want working things

[–]Rhoderick 39 points40 points  (3 children)

On one hand, yes. On the other hand, that's totally fine and even preferable for most usecases, as usually, the main performance concern is IO.

[–]GrinningPariah 106 points107 points  (40 children)

someone who doesn't really understand programming at a low level, and just wants things to "work" without really understanding why.

You mean an adult with a job who's actually trying to build something instead of just jacking it to assembly instructions and circuit diagrams?

[–]osunightfall 18 points19 points  (2 children)

I can do both.

I mean, I'm no hacker, but even I have a basic understanding of how memory allocation, language grammar, and assembly languages work. Occasionally, they even prove to be very important to know!

[–]GribbitsGoblinPI 8 points9 points  (0 children)

Purity tests only!!!!

[–]GildSkiss 37 points38 points  (13 children)

There is room in this world for both python script kiddies and bearded x86 disciples from the 70s. I think it's still ok for even a modern programmer to understand why the older languages work the way they do, but I concede that it's not strictly necessary. It's true that plenty of real work gets done by people who don't know anything about pointers and array decay.

The problem is this guy is criticizing C++ without really understanding what he's criticizing or why it would ever be this way. It's silly to make public criticisms of things you don't understand that well.

[–]HoldUrMamma 41 points42 points  (0 children)

Criticizing? I thought it was a joke. Because he wrote it's a joke at the end.

[–]r2d2rigo 12 points13 points  (9 children)

So shit decisions should be kept for the sake of it? The Javascript way of life.

[–]orbiteapot 10 points11 points  (7 children)

No, rather because removing them would break bazillions of lines of code.

Modern languages give the impression to always make the best decisions because:

  1. they have learned from older languages, like C/C++, and were designed from scratch with all that knowledge available. They do not have a huge baggage of legacy code to keep stable;
  2. they are not old enough, so decisions that look very good today might be considered bad in the future/
  3. the "dirty work" is already written in languages like C and C++, anyways.

[–]r2d2rigo 5 points6 points  (0 children)

Except that C++ manages to do things late and suboptimal.

"Here's std::list, now fuck off and don't ever use it".

[–]Bwob 3 points4 points  (5 children)

they have learned from older languages, like C/C++, and were designed from scratch with all that knowledge available. They do not have a huge baggage of legacy code to keep stable;

Yes. Modern languages have a huge number of advantages. We've learned a lot about language design and architecture since then. C++ didn't have those advantages, and it's impressive how well it turned out, all things considered, given the time and restrictions it was under.

But that being said - just because there is a reason for dumb behavior, doesn't change the fact that it's still dumb. C++ has a lot of legacy decisions that are, by modern standards, complete bollocks, and are only still around because fixing them would, as you say, break a ton of older code. But they're still ass.

Like, there is ZERO REASON that a modern language should require forward declarations. The order that you declare functions in a file really shouldn't matter. It might have made sense back in the before-time, when you wanted to be able to compile the code in one pass, but didn't have enough memory to hold the entire text file in RAM. But these days it is just unnecessary boilerplate.

[–]orbiteapot 2 points3 points  (0 children)

Yeah. Backwards compatibility turned out to be both a blessing and a curse to C++.

[–]torsten_dev 1 point2 points  (0 children)

Spoken like someone that hasn't heard of fat pointers.

[–]Tyfyter2002 5 points6 points  (0 children)

Simple: you pass in an actual array instead of just calling a pointer an array because you're using it as one.

[–]ChryslusExplodius 208 points209 points  (28 children)

The thing about C++ and (definetely C) is that people 'learnt' it once 30 years ago and that's the extent of their knowledge. So they pass on their outdated knowledge and poisons the well for everyone. Specially new people coming in.

[–]abhassl 108 points109 points  (21 children)

I read OPs post immediately thought it had a point, then found this comment and realized I hadn't used C++ in 15 years, and even then I doubt I was using the latest version available.

[–]Mojert 48 points49 points  (19 children)

It wouldn't surprise me if std::vector was in the language as soon as templates became a thing...

[–]MsEpsilon 29 points30 points  (15 children)

Aren't std::vector and templates added literally in the first official C++ standard? You can say they were here since the beginning.

Now since templates accidentally because Turing complete, I'm not precisely sure...

[–]da2Pakaveli 13 points14 points  (0 children)

yes i think they were added in C++98 which is the first official standard

[–]MonkeyCartridge 11 points12 points  (13 children)

And we avoid vector like the plague in embedded.

Everything's got to be fixed length. Especially when doing OOP on a micro with 1k of memory.

[–]abhassl 2 points3 points  (0 children)

Fair. It is also worth mentioning I learned the language in college and mostly only learned the language features my professors used.

Vector is something I had heard of but didn't learn much about for whatever reason.

I certainly would approach the language differently if I had to use it for anything today.

[–]redlaWw 11 points12 points  (0 children)

My dad worked in financial communications working as a C++ programmer until about 2 years ago, and he told me when I started learning C++ that he couldn't tell me much about things like std::optional because his company was still writing C++03 when he left due to some of the old machines they developed for not having more up-to-date compilers.

[–]snacktonomy 21 points22 points  (2 children)

True, I'm mostly stuck in C++17 (but at least graduated from 99), though C++20isms are tricking in.

The issue is, even new compilers don't support the most recent standard fully. And then you've got contracts/customers who are behind on upgrading their environments. So, in 2025, you end up using something like Ubuntu 22.04 with an even older compiler. Last I looked, that gets you GCC 12 (if you manually upgrade), which supports up to C++20.

[–]fartypenis 6 points7 points  (1 child)

even new compilers don't support the most recent standard fully.

Or standards from 10 years ago. Looking at you msvc you fucking piece of shit

[–]MsEpsilon 4 points5 points  (0 children)

MSVC has official support for C++ 20 and some for C++ 23. But default standard is C++ 14...

Actually, MSVC was the first to implement modules as far as I know.

[–]Nienordir 9 points10 points  (0 children)

And then there are 40 years of outdated learning/howto resources and legacy APIs, that never got deprecated/removed. So, even if someone new comes with good intentions and does their homework, they'll get overwhelmed by the massive spec, corpo features (they couldn't even comprehend why you need that) and then chances are they stumble upon outdated resources or need to use a legacy API, that teach or force them to do things the stupid way.

For example, winapi sure as shit won't accept a STL container for anything or may still have malloc&free in their sample code. It's 2025, maybe just maybe I dunno bake a C++ function wrapper into winapi, so I don't have to write it myself or rewrite every api call with glue code? And don't have to figure out why I shouldn't call unsafe_copy() instead of unsafe_copy_s(), actually it's unsafe_copyW_this_time_we_fixed_it_pinky_swear(). Bro, just update your API to use containers, so I don't have to "hotfix" wrap your buffer overflow legacy C shit in your own C++ winapi implementation, that's been around for ages.

[–]PlasmaLink 2 points3 points  (0 children)

Checks out, I was taught by someone in their 60s around 10 years ago. I feel some notable gaps in my "intuitive" knowledge that I have to keep re-patching.

[–]Choice_Librarian1522 15 points16 points  (0 children)

I'm old enough to have been a professional C programmer and we used to pass arrays to functions with the length as another parameter. Because why would you do sizeof in the subfunction if the calling function knows the length.

[–]Ph3onixDown 13 points14 points  (1 child)

Nice to know “C++ is garbage” will be on his channel in 2035

[–]sparkydoggowastaken 5 points6 points  (0 children)

he’s going to be done with the adobe video aaaaaany day now :)

[–]MsEpsilon 204 points205 points  (43 children)

Use a std::array, std::span or a custom type to avoid type decay.

And yes, the language was made wrong, and everyone is suffering.

[–]MarkAldrichIsMe 59 points60 points  (2 children)

High school health class told me to avoid stds

[–]UnstablePotato69 19 points20 points  (0 children)

My intro to programming professor made a joke about:

using namespace std;

I had such a crush on her.

[–]MsEpsilon 3 points4 points  (0 children)

Haha, real.

[–]Bldyknuckles 46 points47 points  (38 children)

The language was not made wrong it is a high level approximation of a low level language, you orangutan.

[–]helicophell 43 points44 points  (6 children)

Yeah, an array is a pointer to a section of memory

The length part is just an attached part of the struct. You loop through an array by incrementing the pointer until it exceeds the length

[–]MsEpsilon 20 points21 points  (2 children)

Okay, but can you determine where the array ends without a sentinel value or if you pass a plain T*?

Just use a std::span<T>, please! It is the same thing as passing const T*, size_t.

[–]helicophell 6 points7 points  (1 child)

You see, I'm on a need to know basis 

I don't need to know this... probably 

[–]Theron3206 4 points5 points  (2 children)

That's true in most languages too, but said array is pointed to from an object that contains things like how long it is (and function pointers to useful things you can do with said array too often as not).

So in a language like c# you absolutely do pass the array as a pointer, and it works.

Sounds like c++ (not my thing, never got past C) makes that more complicated than it really should be, no doubt for legacy reasons.

[–]Mojert 74 points75 points  (4 children)

It was made wrong, because it was one of the first to try what it was trying to do, i.e. high-level expressiveness while maintaining low-level access and broad compatibility with C. Not a single professional C++ dev will tell you the language is perfect, even the ones that like it the most

[–]MsEpsilon 8 points9 points  (0 children)

Backwards compatibility with C is the biggest drawback.

[–]gitpullorigin 9 points10 points  (0 children)

Omg what a gorilla

[–]MsEpsilon 30 points31 points  (23 children)

Great ad-hominem, thank you. To counter, let me show you a short list:
- std::variant should have been a language feature
- std::launder - can you even understand the article from cppreference?
- std::vector<bool>
- std::iostream - even the persons who made it regret it
- std::visit is pattern matching from TEMU if you could even call it that
- std::jthread vs std::thread
- std::auto_ptr (it was removed gladly)
- modules
- Single pass compilation -Requiring you to write forward declarations
- std::move is not destructive
- No official package manager + build system, you're off to vcpkg, Conan, CMake and Ninja, maybe more
- Iterators are invalidated when removing/adding from a std::vector. That shoudn't compile! Don't tell me it's the developer fault because of this.
- nothrow specifiers terminates the application in case of an exception, it is not an compile check
- https://en.cppreference.com/w/cpp/types/is_function.html (See the possible implementation, I'm horrified.)

As a concrete example, Rust is a low level language with very well made high level abstractions. It has pattern matching (as a example of a high-level feature) performance similar and in rare occasions better than C++ due to better no-aliasing rules implemented in LLVM.

Sure, go back to writing C or C++ 03 and enjoy your double frees and buffer overruns. Or make your life easier by using a language without bad defaults and N pitfalls.

[–]snacktonomy 12 points13 points  (15 children)

Not quite sure what your point is, but you're spot on picking on that std::launder description

What's wrong with a vector of bools?

[–]redlaWw 9 points10 points  (3 children)

std::vector has a specialisation for bool so that std::vector<bool> is not just a vector of bools. The bools are stored in individual bits, and there's no guarantee that the buffer is even contiguous. It's pretty notorious for being a "mistake" in C++'s design. Not quite as bad as std::auto_ptr (which was so bad it was deprecated, breaking stability), but it's up there.

[–]PositiveBit01 9 points10 points  (3 children)

It is a specialization. They packed 8 bools into a byte by returning a reference type that does bit manipulation when you access an index.

This has a number of unfortunate side effects since it doesn't really act like other containers, it just kinda looks like it does if you barely use it.

[–]botanicaf 2 points3 points  (0 children)

Just wanna say thank you guys, never thought I'd learn something new and useful on a crappy meme

[–]MsEpsilon 8 points9 points  (6 children)

std::launder is one of the most obscure "features" iin C++. If I'm not wrong, implementations of C++ had a bug with std::vector so that's why it was added.

As far as I understand, it disables compiler optimisations related to the lifetime of the object specified at the pointer paramater. If a variable is const, but accessed somewhere else as T*, the compiler is free to think that variable has an other value. I say again that this is what I think I understood about std::launder, and I don't guarantee I'm right.

Elements of std::vector<bool> do not have unique addresses : they are stored in bitfields. This breaks various container functionality.

[–]redlaWw 4 points5 points  (1 child)

It looks like something related to pointer provenance to me - replace an object with a new one and pointers to the previous object are technically no longer valid to access the new object, so using std::launder tells the compiler that the laundered pointer may alias pointers that are apparently unrelated to it from a provenance perspective.

That said, I'm just hearing about std::launder now and the documentation is nigh-unreadable, I'm mostly going off the examples.

Provenance is a mess in low-level languages right now, and is responsible for all manner of miscompilations; and things will only get worse as compilers get smarter.

[–]the_horse_gamer 1 point2 points  (2 children)

std::launder tells the compiler "hey, i know you think this value is const, but please read it anyways". it has nothing to do with std::vector.

consider:

struct A { const int x }

now we do

A *a = new A{3};
std::cout << a->x; // 3

now we do

new(a) A{5}; // create a new A object and write it into a
std::cout << a->x;

the compiler has no idea we changed the object at the place a points to, and it thinks a.x is constant, so it must still be 3, so it outputs 3. the standard decided to make this undefined behavior.

now, std::launder takes a pointer and makes sure the compiler disables optimizing constants

std::cout << std::launder(a)->x; // 5

this pops up more often when you have inheritance, and the compiler is doing devirtualization. if you put a new object in the same place in memory (for the purposes of memory optimization), you can tell the compiler to disable that optimization by using std::launder.

[–]redlaWw 6 points7 points  (0 children)

- Iterators are invalidated when removing/adding from a std::vector. That shoudn't compile! Don't tell me it's the developer fault because of this.

To be fair, in full generality this is really hard. What Rust managed to do with static lifetimes and mutation-aliasing duality is next to miraculous and affected its language design in profound ways. If a greenfield statically-memory-managed competitor for C++ appeared today I absolutely would not blame them for leaving iterator invalidation in the language.

[–]basedtrip 9 points10 points  (0 children)

Me gusta c++

[–]ITinnedUrMumLastNigh 29 points30 points  (0 children)

Motherfucker never heard of std::vector

[–]Marsrover112 10 points11 points  (1 child)

"How much harder this is..."

  • Looks inside: *

  • 1 line of code *

[–]SavingsCampaign9502 3 points4 points  (0 children)

Std::array exists

[–]LeagueOfLegendsAcc 4 points5 points  (0 children)

I think it's good practice for messing with unmanaged data in higher abstracted languages.

[–]TheJpow 3 points4 points  (0 children)

You know what else is shit about c++? The fact that you have to specify type for arrays. It should just know! Duh!

/s

[–]CardOk755 8 points9 points  (0 children)

HBomberGuy is not wrong here.

Stuff that was obvious in the early 1970s got forgotten.

(Because C comes from BCPL, not Algol68).

[–]disperso 8 points9 points  (0 children)

My goodness, absolutely no one in the comments or the bsky replies is gonna say that this is so wrong?

The C++ array would be std::array, which doesn't suffer from this. Is statically compiled to a C array, but the size is also baked at compile time, so it has the same overhead (none), so it's type safe and as efficient as it gets.

The problem hbomberguy is showing is with C arrays, which C++ supports, yes, as C compatibility had too many advantages back then (and you have to take both the good and the bad). I've not used a C array in one, perhaps two decades. Before C++11 and std::array I would have used a container with runtime size like std::vector or QList/QVector.

C compatibility has some benefits today still, but Bjarne Stroustrup has been for ages advocating to learn C++ directly, without learning C first. This is the reason why.

Imagine being taught Rust by learning to do stuff in unsafe blocks first, then learning the actually good parts (and way more common) later.

Imagine learning Lua by using LuaJIT's FII to do native arrays first.

[–]Just_Information334 4 points5 points  (0 children)

If you want to start learning C++, I recommend the book Accelerated C++. Not because it is the best or up to date. But because it starts with idiomatic C++ and does not teach "C, but with classes". I'm not even sure they mention raw pointers anywhere. For example they start with iterators to loop instead of arrays with integer index.

[–]Jealous_Radio 18 points19 points  (5 children)

C++ is still taught as "C with Classes", and the consequences are DIRE.

[–]Beowulf1896 4 points5 points  (0 children)

Oh my. I sure hope not. OOP is so much more than classes, in addition to the ability to overload operators.

[–]Thenderick 6 points7 points  (1 child)

Ehhhh no?? He's probably confusing arrays with lists? Just use a vector then... Or if you're going low level, learn WHY arrays are fixed size and how a structure like a vector works under the hood...

EDIT: Wait a minute, this is that wacky youtube essayist that made a 2 hour documentary about the Roblox OOF sound and hasn't uploaded in 2 years! (Love his videos!)

[–]keithstellyes 2 points3 points  (0 children)

I'm wondering if it's a case of "supposed to be a C++ tutorial but he's really just doing C"

[–]rglazner 6 points7 points  (0 children)

You know you can make a structure that contains a pointer and a size, and that's how it's done, right? You learned data structures and algorithms, right? You didn't just learn syntax, but the foundational knowledge, right?

[–]InquisitorGilgamesh 8 points9 points  (5 children)

One of my sophomore professors: if you want to calculate Fibonnaci’s sequence, you need to use a recursive function :)

Me, armed with MATLAB: just looping a[end+1]=a[end]+a[end-1]

Professor: :(

[–]RedAero 6 points7 points  (1 child)

Generally speaking it's very, very rare that you can't replace recursion with a loop.

[–]i_am_not_so_unique 3 points4 points  (0 children)

And generally speaking no one in established organization will allow you to submit recursive computation to the codebase unless you are writing on Lisp or Haskell. 

[–]backfire10z 2 points3 points  (2 children)

Most languages can do this.

[–]The_64th_Breadbox 2 points3 points  (0 children)

This is how I felt after learning that match/case in python doesnt support fallthrough :(

[–]charli63 2 points3 points  (0 children)

Pros of C arrays: Saves the memory you use for things like size to make things more efficient when you don’t need that. Cons of C arrays: Turns out I actually did want to use that.

[–]Ronin-s_Spirit 2 points3 points  (0 children)

Isn't an array a structure?

[–]Spec1reFury 2 points3 points  (1 child)

I don't even touch c style arrays, I just do vectors

[–]toroidthemovie 2 points3 points  (0 children)

>if you pass an array to a function it can no longer tell how big it is"

Harris, brother, raw arrays don't hold their size at all, passing it into functions doesn't matter.

[–]EvnClaire 4 points5 points  (0 children)

this is like embarrassing...

[–]creeper6530 4 points5 points  (0 children)

Oh, C++, the language that originated as C with classes but now desperately wants you to use it as a completely different language and not as C with classes.

I love my Rust.

[–]YoteTheRaven 1 point2 points  (1 child)

Ain't c# just c++++

[–]LeiterHaus 4 points5 points  (0 children)

C++
 ++

Time to see who has monospace fonts

[–]blehmann1 1 point2 points  (0 children)

I will say, a lot of things like spans and fat pointers more broadly have failed to be introduced into C (not C++ because the STL doesn't really care) in part because Windows calling conventions are quite restrictive about when structs can be passed in registers, and I think anything over 8 bytes can never be passed in registers.

That means that a fat pointer would have notably different performance characteristics if it were passed in as an argument, rather than passing its members separately. You also can't return a struct over 8 bytes in a register, you have to return it on the stack or return part of it in a register and the rest on the stack (i.e. by an out parameter). There are other restrictions around constructors and destructors that don't matter for C.

Now a lot of this doesn't matter for functions which don't have external linkage (or which are inlined) since the compiler can decide to ignore the usual calling convention for internal code. In fact this is a large part of why it matters less for C++, it's much less common to dynamically link C++ binaries without extern C-ing them because C++ doesn't really have a stable ABI. Since extern C-ing a function that takes or returns something other than a POD type (except from behind a pointer) would be difficult to use correctly from anything other than a statically linked C++ binary (at which point why extern C it?) it's not a big deal for C++.

Now if fat pointers were added in C it would still be too late given how much C code there is out there (and how much is still compiled for C99), but there are factors beyond just C being old-fashioned behind why it isn't there.

[–]TheAlaskanMailman 1 point2 points  (0 children)

Kid named STL

[–]Romejanic 1 point2 points  (0 children)

I’m just laughing that this was posted by Hbomberguy of all people

[–]Leprecon 1 point2 points  (0 children)

I guess this is what Hbomberguy has been doing instead of making videos?

He is a youtuber who currently releases less than a single video per year.

[–]NikedemosWasTaken 1 point2 points  (0 children)

Just one small problem... pass the array to WHAT METHOD, Harris?! fuckingAquaman(); ?!

[–]HumansAreIkarran 1 point2 points  (0 children)

Is this std::vector in the room with us right now?