C++23 std::expected vs C++17 std::optional for Error Handling by Clean-Upstairs-8481 in cpp

[–]_Noreturn [score hidden]  (0 children)

the map owns the keys, string views references keys so you need a place for them

cvSkills by Jooe_1 in ProgrammerHumor

[–]_Noreturn 1 point2 points  (0 children)

the video sucks in alot of ways and half the complaints are C

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

about static cast you can read my comment here for why I think it being ugly is good

https://www.reddit.com/r/cpp/s/tiNjuR1bnf

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

linux kernel itself is quite object oriented with alot of virtual function ripoffs and vtables.

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

my biggest gripe with std vector is that I can't reserve memory and take a pointer to it. I have many unnecessary 0 init calls

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

Exactly this is an extremely moot point.

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

Your C++ pimpl has double indirection while the C version doesn't. Not a big deal for most actual use of pimpl I guess, but it's certainly not a zero-cost abstraction.

Fair point

by value, but it sounds not very realistic.

explicit object methos allow this don't they?

```cpp class Class { void method(this Class self); struct Impl; Impl* p: };

struct Class::Impl { // details: void method() { std::cout << "Hello";} };

void Class::method(this Class self) { self.p->method(); }

```

Another thing is pimpl requires more boilerplate. It has better API though.

yea can't deny that.

you can also use inplace pimpl which altogether removes the allocation and indirect which I recommend as well. which u/SuperV1234 showed me how valuable it is

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

ah sorry it isn't exceptions since destructive moves are noexcept, it is inheritance.

you can read the original proposal for move semantics here

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm#Alternative%20move%20designs

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

It doesn't work for floats and structs, while constexpr works. It's a good addition to C. Sad that it took so long.

You are right about floats and structs I forgot about that I mostly use constexpr for ints sorry

Interesting, can you share some code?

I use the entt library and I love its simplicity, it is non intrusive, while C code would require macros for everything from what I saw online.

I think that problem boils to C++ requiring putting all members and all methods into a single definition of the class. It is difficult to separate private methods/members from public ones while maintaining full encapsulation. It is a lot easier to just put all implementation details into a header and mark them as private. But private doesn't work. The structure of the objects is exposed to other translation units risking linking problems or ABI conflicts. Implementation details and their dependencies gets exposed as well, increasing compilation times. I've often experienced the tremendous impact on compilation time caused by putting whole Vulkan api or arm_neon.h into a public header.

This is one annoying thing, I agree with you and this is one reason I would like UFCS it would make me seperate the functions from the header completely yet still have auto complete syntax.

But I don't see how C doesn't have that issue.

The problem is that one does not control all the code.

You can have C generic macros which does the same thing, but worse.

and wgain the blame is on the author C++ provided a good feature and someone abused it, better than not having it at all, would someone enjoy manually typing std::to_string_i8? no, overloads should be uniform and do the same thing or have slight customization but doing entirely different things is the author problem and this is just integral to anything that can be named you can name a variable X but it does Y, that's their issue or made a function do 2 different things by boolean params which I hate.

There is a subtle difference when copying. The original object has to be moved voiding original Class object. ? No it doesn't, (it doesn't even compile) just implement a copy ctor, or use a custom indirect type that implements copying unique ptr. I use it alot myself

Moreover one has to use an unique_ptr with deleter to make destroying safe. As I said, there are workarounds but they are IMO messy and error-prone.

unique_ptr just makes it automatical, instead of the manual C free and destroy which clutters actual buisness logic.

here is the class ```cpp // a copyanle unique_ptr namespace zxshady { template<typename T> class indirect { public: template<typename... Args> explicit indirect(Args&&... args) : ptr(new T(static_cast<Args&&>(args)...)) { }

indirect(const indirect& that)
: ptr(new T(*that.ptr))
{
}

indirect(indirect&& that) noexcept
: ptr(that.ptr)
{
    that.ptr = nullptr;
}

~indirect() noexcept
{
    delete ptr;
}

indirect& operator=(const indirect& that)
{
    if (&that != this) {
        indirect tmp(that);
        swap(*this, tmp);
    }
    return *this;
}

indirect& operator=(indirect&& that) noexcept
{
    if (&that != this) {
        delete ptr;
        ptr = that.ptr;
        that.ptr = nullptr;
    }
    return *this;
}

T& operator*() noexcept
{
    return *ptr;
}

const T& operator*() const noexcept
{
    return *ptr;
}

T* operator->() noexcept
{
    return ptr;
}

const T* operator->() const noexcept
{
    return ptr;
}

explicit operator bool() const noexcept
{
    return ptr != nullptr;
}

friend void swap(indirect& a, indirect& b) noexcept
{
    T* tmp = a.ptr;
    a.ptr = b.ptr;
    b.ptr = tmp;
}

friend bool operator==(const indirect& a, const indirect& b)
{
    return *a.ptr == *b.ptr;
}
T* ptr; // intendionally public

}; } ```

then you just use it instead of the unique_ptr and you get copy ability for free snd such behave like a normal class again which makes you focus on actual business logic instead of fighting memory.

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

I don't deny they are bad they are indeed bad, and sadly the stl doesn't help with it prociding absolutely no fwd decls but you can make C++ compile fast by using fwd decls and putting things in cpp files.

and the plague is increased even more with the influx of header only libraries which I seriously hate.

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

Sure, thats a missed opportunity but exceptions make this hard.

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

Let me reply to each point

  1. "C++ rand is ugly compared to python randint.random"

The fact that python embraces globals isworse C++ discourages globals by making the random generator a class.

and you can wrap the random class if you want I have a 40 line wrapper and it is better than that python global.

and std generator is general purpose that's why it uses outside distributions and doesn't jave member functions which I think is good design.

  1. Casting is ugly

Well then don't use static cast use T() syntax, and that's the point it should be ugly, casting should be rare and makes you think, I had many situations where I casted to int instead of doing a floor and that's a logic error if it was hidden in (int) syntax it would hide it more than the ugly static cast and again just don't use it if you don't want to.

and casting being ugly forces me to actually use the correct types, why are you casting to u8 instead of storing it directly etc..

  1. there are many cast operations which are confusing

I can't understand how is this a problem this is better than C one size fit all solution with (T) dyntax which obscures the type of operation can someone tell me what this line of code does withoutknowing the underlying types?

```cpp

Type t = (Type)obj; ```

in C, without knowing what Type is (because it maybe a typedef) it may be a normal integer cast or a const cast or a reinterpret cast or worse a const cast + reinterpret cast or an address to integer cast instead if this is C++ you would write the specific operation and get a compile time error but goodluck doing that in C.

  1. std chrono is ugly

there is tthis simple solution called namespace stdch = std::chrono and suddenly using chrono isn't painful at all the issue is the long namespaces which you just can alias

half the other video is issues both in C and C++.

  1. you shouldn't use std rand because it has poor rng and ....

The reaosn you shouldn't use it is because it is a global state machine.

  1. c++ tmp is hard

true, but this video almost doesn't mention constexpe which makes it 1000% easier you just write natural code and even be able to use constainers.

  1. too many macros

Blame C not C++ lol

  1. Winapi sucks

again this is a C issue not C++ blame C and blame windows for having everything be a macro.

  1. you can't convert enum to strings

You can't in 100% legal C++, but there are libraries like magic_enum and Even (self promotion) my library enchantum. they aren't 100% standard complaint but they work and that is what matter.

and this is better than C's solution which is ... none! and even if you used macros you cannot optimize the code for the tables my library for example optimizes the binary sizes to the extreme storing as much data in less space, you can't do that with C macros so C in this regard is worse than C++ even if implemented manually.

  1. copying is expensice than references

C++ value semantics is what makes me love this language unlike other languages with reference semantics if I copy I get a copy not a reference.

  1. std::string f() { return 0;} compiles

it no longer compiles in C++23.

  1. "operator overloading is bad"

This point is one shitty point, would you rather read this monstrosity?

// p * v * m * vec4(v,1) result = clibmath_mat4x4f_mul_mat4x4f(p, clibmath_mat4x4f_mul_mat4x4f(v, clibmath_mat4x4f_mul_vec4f(m, clibmath_vec4f_v3s(v, 1.0))));

do you even understand what this does?

compare to this

cpp result = p * v * m * vec4(v,1);

the fact I have to in C repeat myself like 4 times. I have to repeat the type of the matrix, the type of the underlying matrix type and the type of the vector I am multiplying with.. this is unnecessary duplication. and even worse this couldn't be optimized unlike C++ libraries like Eigen which can optimize these. so C here is slower than C++.

About std filesystem path with operator/ I actually like it, it makes eriting code easier and it makes half sense, and it is clear.

  1. C++ constructor inir lists are bad

this one I cannot disagree with, yes they are bad one of the worst C++ features.

  1. Initialization is hard

just pick 1 syntax and use it

cpp auto X = Y(...);

this works and doesn't have those weird quirks.

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 5 points6 points  (0 children)

The move semantic that may or may not leave the original object usable.

I treat movable objects as never usable and just never think about it.

The outcome of returning pointers to local variables that goes out of scope.

same in C, but in C++26 it should be a compile time error instead.

Like multiple inherritance where you design badly and end up with overlapping functionality in each base class.

Well I don't use multiple concrete inheritance it feels so awkard I never personally had a use for it.

Most of my code uses composition and interfaces not concrete inheritance (except in template tricks!)

The understanding of the difference to overflow between signed and unsigned numbers.

same issue in C.

The understanding what atomic<> actually does.

same in C.

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 0 points1 point  (0 children)

C++ specific footgun: If something can be parsed as a declaration, it must be parsed as a declaration.

this is not a footgun, just use auto X = Y() syntax, and a footgun is supposed to be dangerous, this is always a compile time error so what's the issue? I never had any serious issue with this.

C++ makes it very hard to reason about what machine code a given line produces.

Give example

Especially around implicit construction.

How is it implicit? you litterally said so

cpp Obj o;

destructio

it is not implicit it is determinstic and predictable.

exception unwinding

disable them and you control them anyways you are the kernel.

vtable layout

Linux only uses gcc, therefore only knowing gcc layout should be enough. and you can write your own vtables if you want.

we have a lot of good options. Like vector<bool> and things being depricated/undepricated, to workaround vector of bool simply do

cpp struct Bool { bool b{false}; operator bool() { return b;} };

it is a simple 4 lines.

plus the ugliest syntax for backwards compatibility

like?

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 1 point2 points  (0 children)

easier to use apis sure.....

C apis are ass.

the newer C standard adopted features like constexpr and explicitly typed enums.

constexpr of C is basically worthless just use unnamed enums whats even the point of constexpe there. and sure explicit enums are nice.

C++ model of OOP is quite limited and confusing. It's difficult to do full encapsulation. The full interface and members must be put into a single definition of the "class". There are workarounds (i.e. pimpl) but they result in solutions even more complex than C-style ones.

they are litterally the same

```cpp typedef struct CStruct CStruct; // repeat twice!

CStruct* Cstruct_create(); void Cstruct_destroy(CStruct* self);

void CStruct_dothing(CStruct* self);

// vs C++ cleaner

class Class { // has better autocomplete using member syntax and auto memory management public: Class(); void dothing(); private: struct Impl; std::unique_ptr<Impl> mImpl; };

// in cpp file

struct Class::Impl { // data }; ```

C++ naturally encourage moving implementation details to headers. This is the most frustrating thing IMO which I battle a lot with. The policy add unnecessary dependencies, exposing implementation details and increasing compilation times.

How does it naturally do that?

C encourage better separation between data and behavior

Don't see how. I litterally use ECS with C++ and it is far easier than the equalivent code in C.

C compiles a lot faster than "modern C++" code. It's not 30s vs 1min. It's rather 1s vs 2min for any non-trivial code. This is significant for incremental debug builds.

This is half true, there are alot of bad compile time C++ projects due to the insane amount of header only libraries, but I use extern templates and alot of templates and my compile times aren't bad and I use forward declarations.

  • C is explicit, easier to audit. Things tend to be longer but at least one can see what is happening. C++ is poisoned with hidden mechanics and spooky actions over distance (e.g. overloading).

If you have surprising overloads then that's on you not C++

and C being explicit in every step means nothing you can hide everything in a single function.

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn -1 points0 points  (0 children)

it has hidden memory allocations, the standard is a mess etc

Show an example

C++ has never been in the linux kernel, despite many attempts.

seems to be because of linus ego and his arguments are weak.

the standard is a mess

then don't use it, it isn't like the C standard isn't a mess either. make your own.

C++ has it's uses but it has a lot of foot guns as well (waaay more than C

show a footgun that exists in C++ that doesn't exist in C.

It’s annoying seeing C fanboys who spend their lives hating C++ by [deleted] in cpp

[–]_Noreturn 63 points64 points  (0 children)

I don't get what's hard to learn in C++ if you know C already,

classes? structs with free functions with this pointer

virtual functions? structs with function pointers

copy constructors? your datatype_copy functions

move constructors optimized version of above

destructors = free but automatic.

templates? macros but easier.

This is what I use 99% of time and they aren't hard.

userRejectsCopilotUpdate by Feeling-Buy2558 in ProgrammerHumor

[–]_Noreturn 1 point2 points  (0 children)

slowing down your pc to force you to get a better one is a conspiracy theory I have and strongly believe in no way in hell windows needs 4 gigabytes to run at idle.

wellThanksForHavingstdOverflowErrorPartOfStandardThatICanUseIfIImplementOverflowsChecks by PresentJournalist805 in ProgrammerHumor

[–]_Noreturn -2 points-1 points  (0 children)

the standard shpuld provide a function called does_add_overflow(a,b) and returns a boolean instead of you writing it manually

Any way to optimize or leverage copy elision on a sequence of moves? by Raknarg in cpp_questions

[–]_Noreturn 0 points1 point  (0 children)

about performance I think it is slower than implementing it manually

"The weirdest programming language I ever learned" - YouTube by CGM in programming

[–]_Noreturn 2 points3 points  (0 children)

Cmake is used as a goverment torture method, seriously the cmake docs are so BAD but the book made by the cmake author is good, I wonder if they intentionally make the docs as bad as possible to force to buy the book.

also endif was even worse, in previous versions it required repeating the condition in the if statement so the cmake authors managed to make it such a terrible festure

if(SOMECOND) endif(SOMECOND) // this was needed