Live data from Hacker News

The beauty and simplicity of the good old C-style void* in C++

giodicanio.com

21–30 of 182 posts

Re: The beauty and simplicity of the good old C-style void* in C++

#21
I think that the author is right in everything he says and yes, there is beauty in it.

However, the antithesis is also correct that there exist better solutions to solve the issues.

Both premises hold true.

I have an extensive assembler coding background on 6510, M68000, and i486. I had a very hard time accepting that something could be solved faster and more stable in a higher order language while the downside is more memory, more CPU etc.

More and more it turns out that programming languages are something accidentally read by machines and written by humans, even though this premise got destroyed lately by AI.

However, what I love about C++ is, that it has a basic canon of commands that can be used to build nearly everything while looking extremely ugly and hard to grasp if you don't read very slowly and accurately - so it is a very error prone and dangerous thing that rightfully got substituted by better constructs that allow for better distinctions as well as usage.

I could do everything in assembler (Hey Python users: you know that in the end everything ends up as machine code, don't you?) but it takes 100x times longer and is constantly reinventing the wheel.

Have you ever started to get into the intricacies of bit signs? No? Well, you should definitely, and to this day it gave me a lasting impression when I started wrapping my head around it, when I was 10 to 11 years old hacking my way into the world of assembler programming on C128.

You don't want to take every concept into consideration. You don't want to take interoperability into consideration. All the time!

You want to focus on the problem to solve, not the implications of the implementations all the time.

I am having such a blast very often using Python since it just works with much cognitive distraction about which language construct to use in order to get the machine doing what you want. It is so capable, enable it, to simply ensure within boundaries that the compiler uses the best decision given the context, which is up to analysis.

That's why I stopped using C++ or more precisely stopped any attempts and trying to be smart or fancy. I got to re-read and maintain the code month to years later and history showed, I don't marvel at how magic the line works and brutally smart I was at the time, but simply hate me for obscuring something in a line, that could be well understood if I had used 10 lines, while the compiler gives a damn anyway.

C++ is still necessary but every discussion to this day is about the point you made: every digit counts - and also which position, context etc. You got to be very prolific in order to put into a line what other put into 10.

Is it worth it? No.

In early days it was the correct decision. Memory was sparse, CPU power slow, and the language was small compared to today.

The last time I felt comfortable with a "assembler kind feeling" was with JavaScript before ES6. Peak jQuery level, with the most coolest concept only JavaScript has: Function.prototype.toString()

John Resig will have his place in my programming heroes olymp, who revealed this secret for me, and it opened my eyes for the beauty of higher order languages.

I admire C++, but so do I Python.

But I hope I won't have to ever use C++ again.

Re: The beauty and simplicity of the good old C-style void* in C++

#22
post #2

> It seems that some people are really losing the taste for good readable code. It seems that some people never had taste for good reliable code. Use `void ` and now any error whatsoever is a direct undefined behavior. Moreover `std::span` clearly says that you are not* taking ownership of the memory (even though the language does not check it of course), while `void *` does not. I understand that people can have man…

> A truly zero-cost abstraction

Sadly the MSVC ABI makes std::span and std::string_view a pessimisation:

https://github.com/tringi/win64_abi_call_overhead_benchmark

https://godbolt.org/z/7baaox7re

Re: The beauty and simplicity of the good old C-style void* in C++

#23
This post post is honestly speaking a bag of garbage and ill advises:

> Some good old habit from C can still be positively used in C++, like the void* pointer and the size parameters.

That's garbage.

There is a clear interest of passing both size AND pointer in a single parameter like `std::span: It bind both value together and guarantee that you do not mess with the size of your buffer.

Pass "data" and "size" parameters through a chain of 5 function calls and there is a non-null probability that you passed "other_size" instead of "size" somewhere. This pattern happens everywhere in old C codebase and has been the source of countless security vulnerabilities and random buffer overflows for decades.

All modern languages (including freaking minimalist Golang) have now a "slice/span" concept built in.

It is not just to annoy programmers (and allow them to complain about 'complexity' in blog posts) but because it is a major improvement in term of memory safety and in term of reducing user errors.

> It seems that some people are really losing the taste for good readable code.

If 'span' or 'span' are unreadable for you. The problem is not span, the problem is you.

These are concepts that has been existing for decades in almost all modern programming languages.

Even in conservative C++, it exists since 2014 in the GSL, in Qt and in boost.

And the interface is no different from vector...no excuse here... It is itself the most basic data-structure in C++.

> Why should people complexify and uglify their C++ code with the uint8_t pointer (or std::byte), when void* works just fine??

Sure. Let's extend the logic: I do propose also to replace all typed arguments with a void* pointer.

Because after all: 'It will just works fine' right ?

Type-safety and clear interface are overrated, we could all use only bytes and remove interface all together to get a closer experience of Fortran 77.

/irony

> Or maybe something even more complicated, like this? > template void DoSomething(std::span data)

First that is non-sense.

If you want to pass a mutable buffer of byte, the correct signature is:

``void DoSomething(std::span data)``

There is no need for template signature here. You are making things up.

Second, there is also no need for the N parameter

``span`` is only used when enforcing a buffer with its size known at compile time is desirable. It can be for vectorization (e.g buffer is a multiple of the SIMD line) or to make it explicit in the interface (e.g for bloc cipher for instance)

> states that the pointer points to input read-only memory (_In_reads_)

You do that by using `std::span` in any C++ codebase.

The fact he brags about that as "an advantage" for separated parameter passing just show currently how little is known here.

> My Pluralsight Courses

The kind of C++ code proposed in this blog post would be straight be refused in any PR in almost any serious organization with a proper review process.

So bragging about it on a blog while proposing some C++ teaching is audacious to say the least.

> To finish on that.

The sad thing is that there would be very valid criticism on `std::span`:

- Span does not do boundary check on access by default. Which is a bad design decision in 2026.

- It has an impact on compilation time due to the header inclusion

- std::byte is annoying to work with because it is a hack around an enum instead of a proper C++ builtin type.

But the blog post misses all these points entirely and sticks to complaining about 'Old C being better' the same way your family Grand-Uncle still brags about 'lead gasoline being better' for his 70s Pontiac.

Re: The beauty and simplicity of the good old C-style void* in C++

#24
post #2

> It seems that some people are really losing the taste for good readable code. It seems that some people never had taste for good reliable code. Use `void ` and now any error whatsoever is a direct undefined behavior. Moreover `std::span` clearly says that you are not* taking ownership of the memory (even though the language does not check it of course), while `void *` does not. I understand that people can have man…

That is quite common among C developer culture, play loose and brace for impact.

Re: The beauty and simplicity of the good old C-style void* in C++

#25
post #2

> It seems that some people are really losing the taste for good readable code. It seems that some people never had taste for good reliable code. Use `void ` and now any error whatsoever is a direct undefined behavior. Moreover `std::span` clearly says that you are not* taking ownership of the memory (even though the language does not check it of course), while `void *` does not. I understand that people can have man…

> but `std::span` should have been there decades ago Absolutely! I now use it consistently in all new projects where I can afford to mandate C++20. I guess nobody bothered to make a proposal before...

They did in C, from one of the language authors even, and it was not accepted.

https://www.nokia.com/bell-labs/about/dennis-m-ritchie/varar...

By the way, both Extended Pascal, Mesa/Cedar and Modula-2 have them, under the name of open arrays.

Basically it took Go, C# and others for C++ to finally get its span.

C probably never will.

Re: The beauty and simplicity of the good old C-style void* in C++

#26
post #8

> Why should people complexify and uglify their C++ code with the uint8_t pointer (or std::byte), when void* works just fine?? Fair point (although to be honest: 'complexify' feels a bit of an exaggeration here to me), but the answer to this why is simple: document and express intent clearly. The compiler gave you an error first such that you're forced to consider what you're doing. Any seasoned C++ developer seeing…

+1

And SAL annotations aren't even C++ proper.

Re: The beauty and simplicity of the good old C-style void* in C++

#27
post #8

> Why should people complexify and uglify their C++ code with the uint8_t pointer (or std::byte), when void* works just fine?? Fair point (although to be honest: 'complexify' feels a bit of an exaggeration here to me), but the answer to this why is simple: document and express intent clearly. The compiler gave you an error first such that you're forced to consider what you're doing. Any seasoned C++ developer seeing…

It seems unlikely that this is the case, as the author appears to be experienced, but the post reads like the author has never had to maintain a "simple" and "beautiful" function that was mangled into incomprehensibility over the years, and where if a more expressive type signature had been written from the start, it would have restricted the damage caused over time.

Re: The beauty and simplicity of the good old C-style void* in C++

#28
post #2

> It seems that some people are really losing the taste for good readable code. It seems that some people never had taste for good reliable code. Use `void ` and now any error whatsoever is a direct undefined behavior. Moreover `std::span` clearly says that you are not* taking ownership of the memory (even though the language does not check it of course), while `void *` does not. I understand that people can have man…

> I understand that people can have many things to say about C++, and I do as well, but `std::span` should have been there decades ago (...) Decades is kind of a stretch. C++11 introduced smart pointers, and finally getting C++0x out of the door was already a major victory. Given the history of C++, it would be unrealistic to introduce something like std::span before C++17. Meantime, some organizations are still stru…

It could have been there since the beginning, given that open arrays (aka spans) already existed in other languages, and there was even a failed proposal from Denis Ritchie regarding C.

The C++ span proposal came from Microsoft,

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p01...

Re: The beauty and simplicity of the good old C-style void* in C++

#29
post #8

> Why should people complexify and uglify their C++ code with the uint8_t pointer (or std::byte), when void* works just fine?? Fair point (although to be honest: 'complexify' feels a bit of an exaggeration here to me), but the answer to this why is simple: document and express intent clearly. The compiler gave you an error first such that you're forced to consider what you're doing. Any seasoned C++ developer seeing…

I don't have a strong opinion what is better in this case, but my view is:

> document and express intent clearly

Arguably, the void* does that as well?

> Any seasoned C++ developer seeing this knows what this reinterpret_cast means.

Same for void*?

> it's a bit more text to read

If you have to call it many times, this adds up.

> Some might also say it complexifies and uglifies the code

I think the point is that it adds security, which the other options don't. And, it doesn't add complexity on the caller, but only at one place: the implementation.

> makes it non-portable on top of that.

This can be solved.

Post reply on HN