Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The need to define all 5 has basically nothing to do with C++'s heritage. If you allow those operations to be defined, they all must be defined when you define one of them.

There is a neater design in rust with its own tradeoffs: destructors are the only special function, move is always possible and has a fixed approach, copying is instead .clone(), assignment is always just a move, and constructors are just a convention with static methods, optionally with a Default trait. But that does constrain you: especially move being fixed to a specific definition means there's a lot you can't model well (self-referential structures), and that's a core part of why rust can have a neater model. And it still has the distinction you are complaining about with Copy, where 'trivial' structures can be copied implicitly but lose that as soon as they contain anything with a destructor or non-trivial .clone().

And in C++ it's pretty easy to avoid this mess in most cases: I rarely ever fully define all 5. If I have a custom constructor and destructor I just delete the other cases and use a wrapper class which handles those semantics for me.



> The need to define all 5 has basically nothing to do with C++'s heritage. If you allow those operations to be defined, they all must be defined when you define one of them.

I'm sorry, that is not true at all.

Nothing forces you to add implementations, at least not for all cases. That's only a simplistic rule of thumb that helps developers not well versed on the rules of special member functions (i.e., most) to get stuff to work by coincidence. You only need to add a, say, custom move constructor when you need it and when the C++ rules state the compiler should not generate one for you. There's even a popular table from a presentation from ACCU2014 stating exactly in which condition you need to fill in your custom definition.

https://i.sstatic.net/b2VBV.png

You are also wrong when you assert this has nothing to do with C++'s heritage. It's the root cause of each and every single little detail. Special member functions were added with traits and tradeoffs for compatibility and ease of use, and with move semantics the committee had to revisit everything over again but with an additional layer of requirements. The rules involving default move constructors and move assignment operators are famously nuanced and even arbitrary. There is no way around it.

> There is a neater design in rust (...)

What Rust does and does not do is irrelevant. Rust was a greenfield project that had no requirement to respect any sort of backward compatibility and stability. If there is any remotely relevant comparison that would be Objective-C, which also took a minimalist approach based on custom factory methods and initializes that rely on conventions, and it is a big boilerplate mess.


It would be more user-friendly if non-defined members of the 5 were automatically deleted, IMO.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: