Stop using std::vector wrong

  Рет қаралды 33,409

The Cherno

The Cherno

Күн бұрын

To try everything Brilliant has to offer-free-for a full 30 days, visit brilliant.org/... . You’ll also get 20% off an annual premium subscription.
Patreon ► / thecherno
Instagram ► / thecherno
Twitter ► / thecherno
Discord ► / discord
🔗 LINKS
EASTL ► github.com/ele...
Hazel ► hazelengine.com
🕹️ Play our latest game FREE (made in Hazel!) ► studiocherno.i...
🌏 Need web hosting? ► hostinger.com/...
💰 Links to stuff I use:
⌨ Keyboard ► geni.us/T2J7
🐭 Mouse ► geni.us/BuY7
💻 Monitors ► geni.us/wZFSwSK
This video is sponsored by Brilliant.

Пікірлер: 333
@TheCherno
@TheCherno 10 сағат бұрын
What do you want to see next? 👇 Don’t forget you can try everything Brilliant has to offer-free-for a full 30 days, visit brilliant.org/TheCherno . You’ll also get 20% off an annual premium subscription.
@hanspeterbestandig2054
@hanspeterbestandig2054 9 сағат бұрын
A comparison between std::vector and std::list ? 😉 …and then std:set, std::map and the differences of std::unordered_set, std::unorderd_map … 😏
@JohnDoe-sq5nv
@JohnDoe-sq5nv 7 сағат бұрын
@@hanspeterbestandig2054 Instead of just a comparison I'd like to see a video of cases where he has personally preferred one over the other, like what problem did this data structure solve. I've rarely found myself using lists, but when I have they have been invaluable. Rarely see myself using maps over unordered, priority_queues over deques, or stacks over deques. And lots of my usage of various data structures are just out of habit, but I chose them to solve a specific problem they might not be the best solution for.
@gccore
@gccore 5 сағат бұрын
A video about Memory Orders. Did you use any lock-free structure in your game engine? Does it bring any performance to your engine?
@iso-c
@iso-c 4 сағат бұрын
memory safety. shortcuts what you can take so that you can product faster out. how to make code easily readable.
@iso-c
@iso-c 4 сағат бұрын
video about people who optimising their code about replasing list to vector and how much they use their time to it compared to time how much their app will run in this universum.
@literallynull
@literallynull 10 сағат бұрын
Sonic pro tip: preallocate memory beforehand
@UsernameUsername0000
@UsernameUsername0000 10 сағат бұрын
Please don’t forget to add this to the C++ series playlist. A lot of beginners need to see this
@realishak
@realishak 9 сағат бұрын
He says literally the same things in the vector video in the playlist
@danielmilyutin9914
@danielmilyutin9914 6 сағат бұрын
... and some Rusty guys who see only disadvantages in C++ :)
@theairaccumulator7144
@theairaccumulator7144 6 сағат бұрын
@@danielmilyutin9914 rust has the same thing tho idk what they're seeing
@vortexstudios_echo
@vortexstudios_echo 31 минут бұрын
@@danielmilyutin9914 Rusty guys, nice lol
@isodoubIet
@isodoubIet 6 сағат бұрын
The discussion in the second part is wrong in the sense that the only reason you got all those copies was because your instrumentation code forced them to be there -- overload resolution will prefer the manually-added copy constructor over the compiler-generated move constructor. Had you _not_ written the copy constructor, a move would've happened instead. That is, it's not true that you need to supply a move constructor yourself. In the vast majority of cases the compiler will write one for you and it'll usually be correct, particularly if what you have are just dumb structs (even if they contain more complicated types like vector).
@isodoubIet
@isodoubIet 6 сағат бұрын
As for whether one should still use push_back, IMO yes. It's true that emplace_back subsumes the same functionality so in principle there's no loss of expressivity if you just use emplace_back everywhere. However, 1. using push_back signals intent and more importantly 2. it's not a template, so error messages will happen at the call site instead of deep in the standard library in xmemory or some other implementation-specified header. push_back should also compiler faster and lead to a smaller binary, for the same reason.
@ХузинТимур
@ХузинТимур 3 сағат бұрын
Exactly this. There is no need to optimize copies of integer sized PODs (and even 16 integers copying is still OK).
@DubstepCoder
@DubstepCoder 2 сағат бұрын
@@isodoubIet Was looking for this comment ^_^ correct!
@aarong2374
@aarong2374 59 минут бұрын
Does every compiler generate the move constructor?
@isodoubIet
@isodoubIet 57 минут бұрын
@@aarong2374 Yes, it's required by the standard. If it doesn't it's a bug.
@kiverismusic
@kiverismusic 9 сағат бұрын
You mentioning the code review episode which inspired this vid reminds me of a teacher looking at your paper during an exam, then reminding the whole class not to make some very specific mistake 😅
@nordgaren2358
@nordgaren2358 9 сағат бұрын
Technically, std::array is stored wherever the memory you are using for it, is stored. If you have an object that has an std::array, that array is going to be stored wherever that object is. If you put that object on the heap, then the std array is stored on the heap. In your second example, if you make a static array to store the colors, that data would be stored in the .data section or .rdata section. (Or SOMEWHERE within the PE or ELF. I have also seen static data get stuck in the .text section. Haha) The important part is that it's not going to create any additional memory. Just minor nitpick though. :)
@ekaktusz
@ekaktusz 10 сағат бұрын
Another thing I would add to this, is to always mark your move constructor noexcept if you want the vector to use it. In this case it didn't cause problems, since the reserved size, and no vector resize occured in this example. But if a resize did occur, the vector probably would use the copy constructor instead of move if it's not noexcept. So always mark your move constructor noexcept if you can.
@hbobenicio
@hbobenicio 9 сағат бұрын
Great video! Just a side note... 8 calls to malloc (or standard c++ new operator) not necessarily heap allocate 8 times. it allocates in pages of memory, not every call. but I totally got the point of the video, which is awesome btw!
@Raspredval1337
@Raspredval1337 9 сағат бұрын
operating system gives memory to the process in pages, allocators (like malloc) then break those pages into chunks and give the chunks to the programmer. In order to reuse chunks you need to keep track of the chunks. That means you need at least 2 pools of chunks: one for unused chunks, one for occupied chunks. Plus, it makes sense to keep small and big chunks together respectively to minimize memory fragmentation. Even it the call to malloc (or new) looks very simple it's actually not very simple at all
@ohwow2074
@ohwow2074 5 сағат бұрын
That's true. But even with that, allocations are slow.
@ABaumstumpf
@ABaumstumpf Сағат бұрын
6:08 - that is categorically wrong. The cost of using heap-allocation is the actual allocation. Once it is allocated there is no difference anymore. 9:57 - compile that with a not-ancient compiler and optimisation enabled: The result is most likely 0 allocations - the compiler is allowed to remove those. 16:35 - emplace_back would also be 0 allocations - that is mandated by the language. 19:05 - the reason it does not have a move-constructor is cause you disabled it by giving it a user-declared copy-constructor. had you not done that your class would be a simple aggregate-type, those operations would all be compiler-generated (with some other nice benefits) and you'd not see copies/moves either. With vector you only want to use reserve if you either know the exact number of elements already, or you have measured that there is a performance-problem and you have also measured that you can get a good enough heuristic that your preallocation actually is significantly faster. If you dont know then you can very easily end up with nearly the same number of allocations but a lot higher re-allocation and more memory-traffic.
@izikpfirrmann8775
@izikpfirrmann8775 4 сағат бұрын
You also could have mentioned std::span, which is a meant as a view into a contiguous buffer (like std::vector/std::array) similar to std::string_view is a non-owning view into a std::string (or any contiguous buffer of char)
@coarse_snad
@coarse_snad Сағат бұрын
As someone who works with Rust a lot, I'm sad to see std::span mentioned so rarely. We at least have people using std::string_view nowadays, but it's unfortunate that many people don't know about similar generalized concepts. In fairness though, I have colleagues who take arguments as &Vec in Rust and don't think to just change it to &[T], so i suppose this problem is language agnostic.
@PedroOliveira-sl6nw
@PedroOliveira-sl6nw 9 сағат бұрын
Since you touched the subject, it would be nice to make videos about the inline vectors of some libraries and the pmr::vector of the standard library
@xugro
@xugro 3 сағат бұрын
I'm pretty sure the push back function is an amortized constant so preallocating just halves the copies. Misusing the resize can also make it go from a constant to O(n) insertion.
@hanspeterbestandig2054
@hanspeterbestandig2054 10 сағат бұрын
BTW In the meanwhile the owner (Adam) of this Tetris project was so kind to accept my Pull Request in which I taught him about these Issues as part of a Fork of his Project. This means that the latest version of the discussed code is now fixed in this repeating copy of the vectors. This storage then is referenced by a *const reference* that refers to these cached data when needed. Hence the code now performs lazy allocation of the Resources upon the first access and stores (caches) it *on a single point*. BTW its not only the Vector of Colors that are managed within a std::vector).
@brandyballoon
@brandyballoon 8 сағат бұрын
7:37 What stands out the most to me is not darta vs dayta, but the way you pronounce here... heeya.
@hpsmash77
@hpsmash77 3 сағат бұрын
reserving memory beforehand can actually backfire sometimes
@ABaumstumpf
@ABaumstumpf 2 сағат бұрын
Yeah - you want to do that if you know the exact size or at least a rough order of magnitude.
@WolfspiritMagic
@WolfspiritMagic 10 сағат бұрын
I like that video. There is one thing however that I don't get. The function that hooks into the allocation prints a message and increases the counter. But when executed it show way less messages in console than the counter. For example at 10:48 it shows 1 message printed and 5 allocations. I'd expect it to show 5 lines with "Allocated...". Is this just scrolled or what's going on?
@przemeknowak7350
@przemeknowak7350 3 сағат бұрын
I think it also worth to mention that if we use vector that may be resized, it is good to mark move constructor objects that vector stores as noexcept
@erikahlundhelguera
@erikahlundhelguera 10 сағат бұрын
I wonder if this will be about emplace_back vs push_back
@RockTo11
@RockTo11 2 сағат бұрын
I'd say - just use a standard C array. Especially with C's awesome designated initializers. C++ has some way to go to catch up.
@h7qvi
@h7qvi 9 сағат бұрын
Moving amounts to a shallow struct copy, and happens when the source operand is known to be expiring.
@fbafelipe7666
@fbafelipe7666 Сағат бұрын
In the tetris code, when it iterates the vector it is also making a copy of Position. He could avoid that by changing that for to "for (const Position &item : tiles)"
@mr.anderson5077
@mr.anderson5077 2 сағат бұрын
Thanks Cherno, please teach custom allocator, arena allocator next from scratch. Also speak about template specialization using std forward and more about templated classes Thanks a ton in advance
@dn275
@dn275 4 сағат бұрын
Thank you so much for making this video! It’s super helpful for someone like myself who’s self-taught and doesn’t have a good grasp of the inner workings. I really appreciate how you explain the thought process, the different approaches, and show how you can dig in deeper to verify for yourself. You’re a great teacher!
@Jplaysterraria
@Jplaysterraria 4 сағат бұрын
Reserve has a fun pitfall of not following the geometric growth c: this may cause more allocations if e.g. you have a 1k element vector and reserve 100 elements; the reserve would allocate for 1.1k elements, while using push/emplace_back would allocate for 1.5k elements. If the reserve is done multiple times, it can cause real performance issues.
@oracleoftroy
@oracleoftroy 3 сағат бұрын
Reserve is allowed to overallocate, and I believe that using reserve on most implementations will follow the normal geometric growth of that implementation. On the other hand, resize has this issue on all implementations, IIRC. But in either case, caution is needed as it is vary easy to do worse than just letting the container manage its own size. You are right and Cherno should be more cautious recommending manually handling the vector's size. That works best if you know you want exactly N elements and will never change it, but in most cases it is better to just let vector handle it, at least until you have a performance profile showing that it is suboptimal.
3 сағат бұрын
What about implicit move constructors and copy elision?
@wolpumba4099
@wolpumba4099 10 сағат бұрын
I am just trying to learn std:pmr (polymorphic memory resource). This gives more control of where the memory comes from and can help making code that uses std::pmr::vector (and other STL datatypes) more robust and faster. This gives you one solution to store a vector inside stack memory that you allocated with std::array. I just haven't found a good explaination, yet and I'm currently very confused about it.
@loanselot325
@loanselot325 9 сағат бұрын
why no mention of copy elision(C++17 and after) happening in push_back(Data{...})
@hanspeterbestandig2054
@hanspeterbestandig2054 10 сағат бұрын
5:35 Hoppla! 😳 why is std::array stored on the *Stack* ? It uses the storage *dependent* from the context/location* it lives* ! For example: If you use it within a local (stack managed) scope, then you‘re right. But If one uses it globally, then it *does not* use the stack but the global space which usually is the bss section within the program. If a std::vector is part of a class or struct an one creates an instance by using new then the containing array is also part of this memory which is the heap! For std::vector you’re totally right: This container *likely* uses the heap for its storage because since it is dynamic it will (likely) employ new to allocate its storage space and new means heap! However this is dependent from the implementation. Funny side note: In my career I stumbled over an quite clever implementation that attempts to optimize small Allocations by reserving a certain space for its storage as a fixed array (aka intrinsic storage). If this will not be sufficient, then it starts to use new/ delete to expand this Space upon larger storage demands. This design decision was clever for this ( embedded) Software, because the application code was designed not to exceed these limits to keep the performance high. Furthermore Embedded Software should pretend to use dynamically allocation of memory due to the risk of memory fragmentation… But this is another Story…
@lengors7327
@lengors7327 10 сағат бұрын
I think he uses stack intercahngeably with being alocated depending on location (which he should probably clarify to be fair). As for std::vector always using the heap, is this really a requirement? I.e. is it part of the spec? Genuine question, as I would assume it could possibily have a small "stack" allocation (more specifically storage dependent on location, like an array) for small vectors, no? Something like std::string does if Im not mistaken
@hanspeterbestandig2054
@hanspeterbestandig2054 9 сағат бұрын
@@lengors7327Exactly! You got the point! Thanks for this valuable explanations! 👍👏👏👏
@coolbrotherf127
@coolbrotherf127 7 сағат бұрын
One thing that would probably help is professors in college classes actually teaching this stuff correctly.
@kc3vv
@kc3vv 6 сағат бұрын
Keep in mind that sometimes copying is faster than having an additional indirect memory access, especially when things are stored on the stack.
@soonts
@soonts Сағат бұрын
Good for beginners, but here’s a few comments. The C++ standard library is no longer called STL, it was years ago but now it’s just “the standard library”. std::vector is one of the very few standard collections which is OK even for performance-critical stuff. The only few times when I replaced it recently when I wanted to bypass malloc/free C heap i.e. I know my data is very large and I wanna page aligned zero initialized memory directly from the OS kernel i.e. VirtualAlloc or mmap. Modern compilers are smart enough to eliminate temporaries caused by push_back. For simple elements like your example they often automatically inline everything at least in release builds, compiling push/emplace into equivalent machine code.
@borealis75
@borealis75 9 сағат бұрын
Step 0: Consider if the code you are writing is performance critical. If it is not you can maybe sometimes prefer the simplicity of just using the vector 'wrong'. However often code that is not considered performance critical may become it later, so most of the time just aim to optimize early.
@chris52000
@chris52000 8 сағат бұрын
Slow code is bad code. This mentality is why software is slow. See Mike Acton’s talk “Data Oriented design and C++”
@sutsuj6437
@sutsuj6437 8 сағат бұрын
Premature optimization ist the root of all evil.
@JaceMorley
@JaceMorley 8 сағат бұрын
It's good to understand the reliable baseline. Using std::array for fixed size, and emplace_back and reserve in std::vector, isn't premature optimization, it's having a good baseline approach. Using std::list when you don't know it'll outperform a vector is bad because it's not a good baseline to use and is premature optimization for example.
@empireempire3545
@empireempire3545 7 сағат бұрын
@@sutsuj6437 Stop misquoting
@empireempire3545
@empireempire3545 6 сағат бұрын
@borealis75 you CANNOT know if this or that part of the code is or will be performance critical - and once you set it in stone, it is usually very hard, if impossible to undo - not to mention there simply is no manpower to do it. One should always write code which is at least OPTIMIZABLE and non-pessimized. This whole 'dont optimize' mentality from the early 2000's needs to die already. Compute is cheap, but it is not free.
@nerdastics3987
@nerdastics3987 28 минут бұрын
I see the standard template library used a ton in a lot of performance and memory intensive projects, but it's only ever going to be a "standard library" meaning general purpose.
@DaveMacara89
@DaveMacara89 Сағат бұрын
This video sort of confirmed my suspicions of a lot of what I see with Vector usage, e.g. misuse of the ->data() method (underlying pointer).
@cogwheel42
@cogwheel42 2 сағат бұрын
Fun fact: most people pronounced "data" as "DAAduh" until Star Trek: TNG, when a new actual generation of people grew up hearing Data insist on the "DAYduh" pronunciation.
@Hwioo
@Hwioo 25 минут бұрын
Are you now making beginner classes exclusively, can you plz cover some advanced topic as well
@TryboBike
@TryboBike 2 сағат бұрын
For any task where size matters ( giggty ) - where vector sizes reach thousands of elements - the allocation cost incurred by the incremental push_back probably does not matter. Storing objects with a non-trivial copy semantics in a vector is asking for trouble either way - as a push-back ( or emplace ) that forces a reallocation will move / copy the content to a new location - incurring a pretty hefty cost. For games such usually means frame drops. The main benefit of std::array is that it is 'constexpr' able, which may mean 0 allocations, 0 moves and 0 copies.
@dhickey5919
@dhickey5919 3 сағат бұрын
Amazing! Beyond the Tetris example, can you explain what this memory management change might look like in a larger application? Maybe not an air traffic control system but something where larger consequences can play out.
@adrianojordao4634
@adrianojordao4634 55 минут бұрын
If i do: std::vector v(10); This is in the heap? Umm...
@quplet
@quplet 5 сағат бұрын
It's worth mentioning, reserve can be slower in certain circumstances so you should use it carefully Logan Smith made an excellent video explaining why.
@sparsetable
@sparsetable 9 сағат бұрын
VECTA
@ahbarahad3203
@ahbarahad3203 5 сағат бұрын
DUH TAA
@mobslicer1529
@mobslicer1529 2 сағат бұрын
i just wrote an implementation of it, it was super fun (and it helped me fix a lot of bugs in my linked list and memory allocator implementations)
@PlayBASIC-Developer
@PlayBASIC-Developer 9 сағат бұрын
The stack isn't magic it's just is just a chunk of heap memory... The benefits are from cache locality.
@thomashamilton564
@thomashamilton564 8 сағат бұрын
PLUS avoiding the overhead of actually _allocating_ memory - someone has to find a space and do book keeping etc. for you
@SadsaGamer
@SadsaGamer 8 сағат бұрын
Not only cache locality. If you allocate on the stack, it just increases the stack pointer and that's it, whereas allocating on the heap requires some complicated mechanism to find free memory and such.
@דניאלאביב-ו6ת
@דניאלאביב-ו6ת 8 сағат бұрын
Allocating on the heap requires searching for a free block of memory, while stack allocation simply involves adjusting the stack pointer.
@wdavid3116
@wdavid3116 8 сағат бұрын
Well depending on the specifics it may or may not be part of the heap. It is definitely part of main memory like the heap. The benefits are cache locality and speed of allocation and de-allocation. Heap allocation means finding available memory giving it to the process and tracking that it's in use while de-allocation means putting it back in the pool to be reused. Stack allocation involves adding a single value to a register and it can be done once for each stack frame so it more or less takes 0 cycles or at least 0 additional cycles, same for de-allocation but subtracting vice adding.
@mushtaqueahamed1851
@mushtaqueahamed1851 8 сағат бұрын
Stack and heap are both chucks of memory used by program differently, let us keep that distinction. Stack is local to function call frame and scopes, while heap is kind of global to program. Each malloc and free, is some 600+ lines of C code, while stack pointer manipulation is just 1 cpu instruction, that compiler knows statically (at compile time).
@Vencentguo
@Vencentguo 10 сағат бұрын
I was going to comment on the fact that the case made in this video actually demonstrated how good the vector is since the cost of allocation is amortized which is explained a bit later. Also, the copy and move constructor is irrelevant to the topic in using the vector since other data structures will behave similarly to how your customized data type set up copy and move constructors. However, the process of analyzing allocations here is solid and in fact, lacking in most developers I've seen in other language users, so kudos.
@oserodal2702
@oserodal2702 9 сағат бұрын
Shouldn't the colors either be from a template or a struct or decoded from a config file or something. Storing it in a data structure feels kinda wrong, as they'll be used all throughout the codebase as a unit of code and not just some part of the gameplay loop.
@maxscriptguru
@maxscriptguru 7 сағат бұрын
Your a natural teacher. And your editing is spot on too: Short and quick. Love it! fantastic video.
@codewithk0x00
@codewithk0x00 10 сағат бұрын
i was just watch your opengl series suddenly you tube sent me the notifications The Cherno Uploaded new video and i am here.
@xfinnerjx
@xfinnerjx 10 сағат бұрын
Great show and tell of how something and simple as std:Vector isn't the silver of collections of data that a lot of people think it is unless through and planning are used first.
@literallynull
@literallynull 10 сағат бұрын
"sorry, I'm just Australian"
@jzxdrift
@jzxdrift 3 сағат бұрын
Living in Australia and having citizenship doesn't really make one Australian. He's Russian and he doesn't even sound anywhere close to what Australians sound like, their accent is worse than British
@kanecassidy9126
@kanecassidy9126 8 сағат бұрын
can you please make a video about inline, constexpr and static? when which should be used?
@MrCsapotamas
@MrCsapotamas 7 сағат бұрын
can you make an comprehensive video about EASTL, please ?
@YasasTharinda
@YasasTharinda 6 сағат бұрын
with some custom allocators can't we get more optimized vector operations ?
@MattRose30000
@MattRose30000 6 сағат бұрын
Interesting to know where exactly all the overhead comes from 👍
@thomashamilton564
@thomashamilton564 10 сағат бұрын
In Rust the std vector initially starts with 4 elements and then grows to avoid the millions of cases of extra allocations for tiny arrays.
@just_smilez
@just_smilez 9 сағат бұрын
In c++ it doubles capacity when it needs to grow for the same reason.
@thomashamilton564
@thomashamilton564 8 сағат бұрын
@@just_smilez The point I'm making is that in the video the Cherno mentions that there are several allocations when moving from 0 to 1 to 2 to 3 to 4 elements - which are elided in Rust.
@lumek4513
@lumek4513 8 сағат бұрын
@@just_smilez it's times 1.5 actually, but close
@qqshutup7175
@qqshutup7175 8 сағат бұрын
@@just_smilez In msvc++ stl grows by 1.5x
@faresmahmoud-nx2pg
@faresmahmoud-nx2pg 7 сағат бұрын
​@@lumek4513this is only with msvc and clang tho , gcc doubles the capacity.
@MadMetalMacho
@MadMetalMacho 9 сағат бұрын
What does std::array do over just "Class name[8]"?
@ibbles
@ibbles 8 сағат бұрын
A container API, like size(), begin()/end(), front()/back(), index-checked at() etc. Sane copy semantics, i.e. doesn't implicitly decay to a pointer.
@MadMetalMacho
@MadMetalMacho 6 сағат бұрын
@@ibbles thanks, most of that barely makes sense to me coming from C, but I suppose if the compiler optimizes out the overhead then there's no real downside
@sharos404
@sharos404 5 сағат бұрын
​​@@MadMetalMacho Also really useful: The size is a compile time constant, so the equivalent way in C would be to have #define A_SIZE 8 and implement OOB checks manually, where C++20 one can use stuff like std::bit_cast which is like "B = (char*) A" but it checks the static size of the two objects being cast, so it will verify that for example std::array is trivially castable to any plain old data struct of size 8. This really helps against the casting a struct of wrong alignment footgun.
@peepoKT
@peepoKT 5 сағат бұрын
Can also be returned by value
@TheTrienco
@TheTrienco 4 сағат бұрын
For completeness sake, the implementation of array is usually just a wrapper around a C array. It usually adds no overhead, but a ton of convenience.
@halalos
@halalos 5 сағат бұрын
i have a question, doesn’t copy elision get rid of the copies in release mode at least when you just push them back like that creating the instance in place? 17:25
@VitisCZ
@VitisCZ 5 сағат бұрын
Copy elision behavior can vary between compilers so i wouldn't bet on it if you can get guaranteed behavior by writing code a certain way.
@TheTrienco
@TheTrienco 5 сағат бұрын
The main issue is that the rules for when the compiler "may" and when it "must" do copy elision are not something one wants to keep in mind all the time. Explicitly creating them in place involves a lot less guessing (especially for anyone who later reads the code). Though that would make for an interesting video.
@MrAbrazildo
@MrAbrazildo 53 минут бұрын
4:20, if array is the most used, I don't know. But std::vector is certainly more comfortable, and almost as the same speed as array. Even nowadays, when clang seemed to achieve more performance for array, it's only ~5%, according to my benchmarks. Meaning a game (depending on vector performance) with 57 FPS would run at 60 with array. That also means vector is being deployed on stack - otherwise it would never reach this performance. vector is also more comfortable to use because of pushing_back things makes the size grows proportionally, without the worry for seg fault, when reaching stack's limits. But of course, I always use vector::reserve 1st, to avoid new "allocations" at every push_back.
@TheCherno
@TheCherno 2 минут бұрын
std::vector is also an array, I wasn’t talking about std::array specifically
@caitlyn8415
@caitlyn8415 10 сағат бұрын
please create series of Advance OOP for gamedev
@shahoriaprantik6343
@shahoriaprantik6343 10 сағат бұрын
ohh man i would so love that
@captainfordo1
@captainfordo1 8 сағат бұрын
OOP is a big mistake. Just use structs and functions
@empireempire3545
@empireempire3545 6 сағат бұрын
Oh, it's very simple: do not use inheritance. In fact, dont use OOP at all except maybe UI. The correct paradigm for high performance applications is Data Oriented Programming.
@4TechStore
@4TechStore Сағат бұрын
thanks so much can you please make series vulkan?
@impcnrd
@impcnrd 8 сағат бұрын
So much PUSH_BACK against using push_back(). That was the OBJECT of this video. It was very informative to C this video. A++
@asteriskman
@asteriskman 7 сағат бұрын
I swore you were South African! 😂
@strtale
@strtale 2 сағат бұрын
Which Visual Studio theme is this?
@YarGnawh
@YarGnawh 7 сағат бұрын
i watched so many of your videos and i think i understand all the best practices, but i still can't, for the life of me, write a C++ application. 😑
@TheTrienco
@TheTrienco 5 сағат бұрын
I'm glad I started with C++ "way back then", got to use it at work almost exclusively and could add all the new stuff gradually. It's also not as easy as saying "just learn old C++ and add the rest later", because a lot of the new stuff is actually making things a lot simpler. Now I wonder if there is a good "current C++ for beginners" resource that filters all of that down to a manageable selection (and for the love of everything good in the world doesn't start with "let's first learn C, so you later have to unlearn everything, because most of it is now all bad practices and I just wanted to teach you how to build a combustion engine before teaching you how to drive a car).
@them4309
@them4309 3 сағат бұрын
Excellent C++ talk as usual.
@mamalinio
@mamalinio 9 сағат бұрын
Amazing video. Bravo!
@d-shiri
@d-shiri 9 сағат бұрын
great explanation. thanks
@ABrainrotAwayFromHeaven
@ABrainrotAwayFromHeaven 7 сағат бұрын
Covering the basics
@MukundKannan
@MukundKannan 3 сағат бұрын
pls share your vs theme
@Skipper0x
@Skipper0x 10 сағат бұрын
been here from University to 6 year of working as a game dev, and your teaching still amaze me
@bencebalint1956
@bencebalint1956 6 сағат бұрын
Easy subscribe, cheers KZbin algorithm
@gilsonjustjr
@gilsonjustjr 3 сағат бұрын
beautiful !!!
@Montazeran8
@Montazeran8 55 минут бұрын
❤❤❤
@al8905
@al8905 8 сағат бұрын
top bloke
@RandomGeometryDashStuff
@RandomGeometryDashStuff 7 сағат бұрын
04:28 me arguing: signed 32 bit integer
@xOWSLA
@xOWSLA 9 сағат бұрын
Lovely.
@Tornnaz
@Tornnaz 10 сағат бұрын
ayy we early today
@ArcShahi
@ArcShahi 10 сағат бұрын
17:50
@guilherme5094
@guilherme5094 7 сағат бұрын
👍
@Raspredval1337
@Raspredval1337 10 сағат бұрын
8:30 that's UB. You've effectively replaced the default *operator* *new* allocator with *malloc* . It's not guaranteed that default *operator* *new* uses *malloc* , thus memory blocks allocated with *new* \ *delete* might not be compatible with *malloc* \ *free* The 'correct' solution would be to also overload the *operator* *delete* with a *free* wrapper
@aboliguu1168
@aboliguu1168 9 сағат бұрын
Yeah but he was only allocating simple ints and in a very simple example program. Doesn’t matter
@Raspredval1337
@Raspredval1337 9 сағат бұрын
@@aboliguu1168 UB always matters. Even if the program does what you think is supposed to happen, UB prevents some (a lot actually) optimizations. It might be some micro optimizations here and there, and sometimes compiler can opt out huge chunks of dead code or even replace heap allocations with stack allocations. Plus, nobody wants their code to segfault, even if the only downside is an annoying error beep at the end of the program 🤷
@aboliguu1168
@aboliguu1168 8 сағат бұрын
@@Raspredval1337 the point is that in this TINY example program it didn’t matter. You are splitting hairs here.
@simonw3858
@simonw3858 7 сағат бұрын
Whats UB?
@Raspredval1337
@Raspredval1337 7 сағат бұрын
@@simonw3858 Undefined Behavior. Basically, there're some things, that a language (or library developer) assume as correct. And if the user breaks that assumption, then it's on the user. Good example is indexing into the memory that doesn't exist(like int array[ 5 ]; std::cout
@98danielray
@98danielray 6 сағат бұрын
Calling a mathematical vector a "fixed length sequence of numbers" is really sad
@Awesomekid2283
@Awesomekid2283 2 сағат бұрын
Even if it is just an example, seeing for and if without curly brackets is killing me.
@ibbles
@ibbles 8 сағат бұрын
We never saw the counters printed for the std::array case. Would that have 0 copies and 0 moves?
@juanmacias5922
@juanmacias5922 5 сағат бұрын
vector should have been called something like dynamic array, or list lol
@__christopher__
@__christopher__ 5 сағат бұрын
List is already taken for the class that implements a doubly-linked list.
@juanmacias5922
@juanmacias5922 5 сағат бұрын
@@__christopher__ oof lol
@Daethalus
@Daethalus 6 сағат бұрын
I have a better one: just stop using std::vector
@AK-vx4dy
@AK-vx4dy 3 сағат бұрын
@14:49 Wow, wow...magic number, dry violation, constant duplication and possible buffer overrun when you forgot change one number... you made this code worse, faster but worse 😉
@shipweck6253
@shipweck6253 3 сағат бұрын
can you elaborate?
@AK-vx4dy
@AK-vx4dy 3 сағат бұрын
@@shipweck6253 if you increase limit of loop for example to 6 and forget to change .reserve, resize or declaration in version not using push or emplace but indexing, you write past allocated vector
@kostiapereguda
@kostiapereguda 4 сағат бұрын
The more I work with c++, the more I understand people who prefer Java
@not_ever
@not_ever 4 сағат бұрын
This would be a sick burn if the punchline wasn't Java
@askeladden450
@askeladden450 4 сағат бұрын
All this is vector stuff is true for any language, not just c++, some nuances aside.
@12affes
@12affes 10 сағат бұрын
I would also recommend using std::span for function arguments.
@giorgos-4515
@giorgos-4515 9 сағат бұрын
Can you explain why? Is span the more generic type in C++?
@playa.9187
@playa.9187 9 сағат бұрын
​​@@giorgos-4515Basically it's the same as passing std::string_view vs passing std::string to a function. Doesn't copy or allocates any memory. Don't know about std::span but std::string_view internals is string length and pointer to first string character. I believe that std::span works with any std array and not just vector
@12affes
@12affes 8 сағат бұрын
@@giorgos-4515 what @playa.9187 said :)
@qqshutup7175
@qqshutup7175 8 сағат бұрын
@@giorgos-4515 Basically it contains a pointer + size internally pointing to a known type, you could recreate std::string_view inheriting std::span and implement string operations in 5 minutes... Very useful for passing dynamic arrays/vectors without having to pass the original array/vector by reference. There are cases where you want to slice an array or vector and pass only elements between 0 and size(), you can do this with std::span because it will internally point to the contiguous memory of the array/vector, just note that std::span does not own the memory as well as std::string_view.
@giorgos-4515
@giorgos-4515 6 сағат бұрын
@@qqshutup7175 For slices it seems like a great option, for not copying memory a const ref seems to be enough and more familiar for most people, i need to dive a bit deeper to understand its significance.
@aditya_sharma
@aditya_sharma 6 сағат бұрын
6:07 Can someone explain how stack is "faster to use". Allocation I understand, but if i just want to store data in memory already allocated in heap, how is it slower? My thinking is, it is the same physical memory which we are using and for allocation, the OS needs to be involved. But what about accessing an already allocated block of memory? I think it should perform identical to stack.
@jcm2606
@jcm2606 6 сағат бұрын
I'd assume it's faster to use due to better cache locality. Heap allocations can be spread across the address space, so you may end up with data sitting on far apart cache lines that wreaks havoc on the cache when the CPU tries to access that data. Stack allocations, on the other hand, exist within a contiguous block of memory and are only logically spread apart, which means that when you access one stack-allocated variable, the others around it are likely within the surrounding cache lines, making it much easier/faster to access.
@ArcShahi
@ArcShahi 6 сағат бұрын
cuz accessing stack variables usually involves a fixed offset from the base pointer (or stack pointer), which is fast because it's a direct memory reference. : ```asm mov rax, [ebp-4] ; Access value 4 bytes below the base pointer add rax, [ebp-8] ; Add value 8 bytes below the base pointer ``` The stack is directly managed by CPU registers like rsp (stack pointer ) and rbp ( base pointer) allowing very fast data movement on and off the stack due to the immediate access provided by these registers. the heap part of memory is not contiguous, so there is an overhead of dereferencing pointers that point to fragmented memory locations. The CPU first needs to read the address from the pointer, and then access the actual data, which adds overhead .
@indigojones4442
@indigojones4442 6 сағат бұрын
@jcm2606 already mentioned better cache locality, but the main reason a stack allocation is better is because a heap allocation involves an extra pointer indirection. Imagine a race to access an int on the stack, and an int stored on the heap. You can read the int off the stack in a single lw instruction. To read the heap allocated value, you have to read the pointer off the stack, (one lw instruction) then read the int from that memory location (another lw instruction) and there is a data dependency between the two instructions, so the second lw cannot be issued until the first one completes.
@Raspredval1337
@Raspredval1337 5 сағат бұрын
@@ArcShahi the overhead is negligible, it's mostly about cache locality
@Djellowman
@Djellowman 6 сағат бұрын
18:00 huh I don't understand how calling data(i) allocates new memory... Am i missing something?
@pierrecolin6376
@pierrecolin6376 6 сағат бұрын
It does if the Data structure contains data members that do dynamic allocations such as smart pointers or vectors. It’s not the case in this toy example, but it often happens in practice.
@Raspredval1337
@Raspredval1337 5 сағат бұрын
@@pierrecolin6376 smart pointers don't allocate memory, they guard a pointer to the memory allocated by the user.
@FerdinandJosephFernandez
@FerdinandJosephFernandez 5 сағат бұрын
It's a constructor, it creates a new instance of the struct on the stack. It's not allocating, but it is causing extra work to be done as the copy constructor gets used to essentially duplicate that newly made Data into the vector.
@吳政霖-b9t
@吳政霖-b9t 5 сағат бұрын
Data(i) is constructed on the stack first, then it is pushed (moved or copied) into the heap for the vector.
@Djellowman
@Djellowman Сағат бұрын
@@FerdinandJosephFernandez Yes i realized this right after posting the comment, which is why is deleted it... youtube shenanigans.
@DeGuerre
@DeGuerre 9 сағат бұрын
Extra protip: Don't forget std::deque as an alternative to std::vector if the size that you need is unknown in advance. Unless you're using Microsoft's implementation, because its std::deque implementation is very, very broken with regard to the number of allocations it needs.
@hoverpillow6106
@hoverpillow6106 10 сағат бұрын
Cherno, have you seen the Lager library? Lager is a C++ library to assist value-oriented design by implementing the unidirectional data-flow architecture.(c) Will it be useful to have it in gamedev? Your opinion is much appreciated.
@videojeroki
@videojeroki 10 сағат бұрын
vector... what a great name...
@Raspredval1337
@Raspredval1337 9 сағат бұрын
arrays are called vectors in math 🤷
@videojeroki
@videojeroki 8 сағат бұрын
@@Raspredval1337 yes, but programming is not always about math. Also, vector is generally used in geometry for an object that has magnitude and direction. Shall we talk about tuple 😅
@qqshutup7175
@qqshutup7175 8 сағат бұрын
@@videojeroki what do you suggest? std::stack_array std::heap_array
@videojeroki
@videojeroki 7 сағат бұрын
@@qqshutup7175 i would suggest. std::arrayd for dynamic size array, and std::array for fixed size array. Maybe 1 generic type of array that uses templates to specify its properties at the declaration: std::array my_generic_array; But that already sounds like a stupid idea
@isodoubIet
@isodoubIet 6 сағат бұрын
@@videojeroki "Also, vector is generally used in geometry for an object that has magnitude and direction. " A function in an L2 space is also a vector, does it have magnitude and direction too?
@fluffydoggo
@fluffydoggo 5 сағат бұрын
Actually really interesting video coming from a managed language background whos learning C++. All im seeing are pain points 😢😢
@nordgaren2358
@nordgaren2358 9 сағат бұрын
I'm quite surprised that MSVCs first allocation for a standard vector is just a single element. I thought most modern languages used like 6 or 12. IDR, there's so many magic numbers, but there have been multiple studies on the optimal number of allocations on your first allocation for a growable array. They also touch upon resizing, usually, and generally the performant option is to use 1.75 or 2x the capacity, when you go to grow the array buffer. I thought GCC did this, but I can't remember. MSVC generally has atrocious implementations for things. Their small string optimization is pretty terrible. 😂_ScaryVal!!!!
@nenadjovanovski1461
@nenadjovanovski1461 10 сағат бұрын
I used to only program in C++ and used to love it, but this surely was an eye-opener. Amazing video! Amazing channel!
@redhawk3385
@redhawk3385 4 сағат бұрын
Wow I've wrote rust for long enough I forgot a lot of "optimizations" rust has are things like you cannot copy vectors, ever unless you call the copy method. Which for the average programmer will force their code to be faster, for not much cost.
@i_Have2BrainCells
@i_Have2BrainCells 3 сағат бұрын
I am pretty sure that I live in a simulation. i recently started learning about vectors and your videos showed up on my feed. Feels weird to imagine, thought its old video but naa...
@oleksiistri8429
@oleksiistri8429 8 сағат бұрын
i remember i read somewhere that vector puts data on the stack if it has small number of elements and only after some size it starts copying it to the heap, but i do not know if its true. p.s. "do not use vector" - very funny, but i am not laughing..
@soniablanche5672
@soniablanche5672 8 сағат бұрын
technically everytime Cherno says "It's stored on the stack" it could be stored on the heap if it's part of a struct/class and the object was created with new
@PFnove
@PFnove 3 сағат бұрын
"Stop using std::vector" would probably be better advice but using it right is a step in the right direction
I used to hate QR codes. But they're actually genius
35:13
Veritasium
Рет қаралды 423 М.
HAH Chaos in the Bathroom 🚽✨ Smart Tools for the Throne 😜
00:49
123 GO! Kevin
Рет қаралды 16 МЛН
SHAPALAQ 6 серия / 3 часть #aminkavitaminka #aminak #aminokka #расулшоу
00:59
Аминка Витаминка
Рет қаралды 1,9 МЛН
Как мы играем в игры 😂
00:20
МЯТНАЯ ФАНТА
Рет қаралды 3,2 МЛН
I redesigned my game
23:32
jdh
Рет қаралды 22 М.
I took the #1 Tech Exam and it was BRUTAL
18:28
Linus Tech Tips
Рет қаралды 1,3 МЛН
Mining Magnetite
16:20
Cody'sLab
Рет қаралды 300 М.
Why Didn't He Get the Job? Let's Find Out! // Code Review
27:25
The Cherno
Рет қаралды 127 М.
WHY did this C++ code FAIL?
38:10
The Cherno
Рет қаралды 259 М.
Why I Don't Like Singletons
29:05
The Cherno
Рет қаралды 67 М.
Demystifying the C++ Compiler!
12:52
Low Level Game Dev
Рет қаралды 17 М.
TETRIS CLONE! // Code Review
36:55
The Cherno
Рет қаралды 37 М.
HAH Chaos in the Bathroom 🚽✨ Smart Tools for the Throne 😜
00:49
123 GO! Kevin
Рет қаралды 16 МЛН