Remix.run Logo
groundzeros2015 10 hours ago

Before move semantics the HeavyObject problem was solved in most cases by specializing std::swap for each container.

The design lesson I draw from this is that pursing a 100% general solution to a real problem is often worse than accepting a crude solution which covers the most important cases.

usefulcat an hour ago | parent | next [-]

That still leaves the problem of when to use std::swap vs ordinary assignment in generic (i.e. templated) code.

Like when std::vector needs to resize its underlying storage (as a result of push_back, for example), it has to decide which approach to use to copy/move items from the old storage to the new storage.

For std::vector<std::string>, std::swap would probably be at least ok if not optimal, but for std::vector<int> it would be overkill and therefore decidedly non-optimal. In the latter case, you want to do memcpy(new, old) and be done, not std::swap(old[i], new[i]) for each int.

I think a lot of the motive for adding move semantics to c++ has to do with giving the compiler enough information to produce results that are both optimal and correct in generic code.

groundzeros2015 10 minutes ago | parent [-]

If the type is trivial you don’t swap, if it is you do.

There were already special cases for this in C++98 in order to optimize for when memcpy and memove could be invoked.

an hour ago | parent | prev | next [-]
[deleted]
dathinab 6 hours ago | parent | prev [-]

my take looking at languages beyond C++ is a very different one

you want a well working general solution which works well (most of the time for most of the "generic code" (i.e. good defaults for the default use-case).

and then add escape hatches for micro-optimizations, micro-control etc.

C++ on the other hand was deeply rooted designed with micro optimizations and micro control first.

"Generic solutions" where then tried to be added on top, but not by changing a badly working abstraction/design but by adding more abstraction layers and complexity on top. And with a high requirements for back/forward compatibility, not just with the language but ton of different tooling. That this isn't playing out well is kinda not really surprising IMHO. I mean adding more abstraction layers instead of fixing existing abstraction layers rarely plays out well (1) especially if the things you add are pretty leaky abstractions.

-----

(1): In context of them archiving overall the same goal with just different details and no clear boundaries. Layering very different kind of layers is normal and does make sense in a lot of situations. Just what C++ does is like layering "a generic system programming language" (modern C++) on top of "a generic system programming language" (old C++) without clear boundaries.

groundzeros2015 5 hours ago | parent [-]

C++ does have reasonable defaults. You never have to worry about move if you are using standard containers or unique_ptr.

But eventually those escape hatches come bite you and you need to worry about.

Complexity is inherent to the system. Wrapping it in a nice interface doesn’t make it go away.

—-

The problem I see is move semantics are a real thing in programming languages where types can own resources.

Most languages just choose not to handle them well or limit their feature set. For example swift tries to use copy on write to avoid it

So eventually feature creep happens and you get borrowing/move.