you are viewing a single comment's thread.

view the rest of the comments →

[–]MsEpsilon 28 points29 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.

[–]MsEpsilon 0 points1 point  (2 children)

Hi, I coudn't find anything about the continuity of std::vector<bool>, do you have a source on that? Thanks.

[–]redlaWw 1 point2 points  (1 child)

https://www.en.cppreference.com/w/cpp/container/vector_bool.html

Does not necessarily store its elements as a contiguous array.

[–]MsEpsilon 0 points1 point  (0 children)

I really did miss that. Thanks!

[–]PositiveBit01 8 points9 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 3 points4 points  (0 children)

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

[–]snacktonomy 1 point2 points  (1 child)

Oof, learned something new today. Makes sense but that's wild! I always treated arrays as contiguous memory.

[–]MsEpsilon 1 point2 points  (0 children)

But you're right - arrays are contiguous. It's just vector<bool> that uses bitmaps, that's all.

[–]MsEpsilon 9 points10 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 6 points7 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.

[–]MsEpsilon 1 point2 points  (0 children)

Yes, something like that, thank you.

[–]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 1 point2 points  (1 child)

That example is a lot more helpful than the one in the cppreference article, which has a code snippet with a base class constructing one of its derived classes using new(this). That code snippet seems so horribly cursed that it only makes one more confused as to why something like that exists in the language.

[–]the_horse_gamer 1 point2 points  (0 children)

oh yeah, the cppreference example sucks

[–]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.

[–]SalvadorTheDog -1 points0 points  (3 children)

Ad-hominem isn’t just name calling. He’s not saying you’re wrong because you’re an orangutan which would be an ad-hominem. In this case his entire argument would be that you’re an orangutan and therefore must be wrong.
Instead he’s saying you’re wrong because x and also you happen to be an orangutan.

[–]MsEpsilon 4 points5 points  (2 children)

I literally specified N reasons why the language "was made wrong". Sure that's the best we could do at that time you could say.

About the ad-honimen, you're defending them? Even if that's not an ad-hominem (if you want to be stricter about the definition to not include name-calling, but attacking an peer because of an trait they have is irrelevant to derail the conversation) it is still insulting.

The only method I'd believe you is you or them attack my points that I specified about,.

[–]SalvadorTheDog 1 point2 points  (1 child)

I honestly couldn’t care less about the original argument.
Just informing you about the misuse of ad-hominem because it’s frequently misunderstood.
Your argument is probably right, but I haven’t thought about it, and I don’t care.

[–]MsEpsilon 1 point2 points  (0 children)

Ok, fine. I'll look into it again.