5 ms·
> Since C++ uses deterministic destruction and freeing, there has to be clear responsibilities defined. In particular, it has to be clear which thread is ultima
by catnaroek 10y ago
> Since C++ uses deterministic destruction and freeing, there has to be clear responsibilities defined. In particular, it has to be clear which thread is ultimately responsible for running the destructor.
Ownership itself is an abstraction that is very useful for manipulating ephemeral resources, and which is very difficult to express in languages where garbage collection is the mandated universal solution for resource reclamation.
> Point being, writing code that would otherwise be "abstract" in Java-land implies (but rarely explicitly defines!) some rigidity in design with respect to how long objects need to be around for different threads to use them.
When you care about ownership, “who frees this object” isn't an implementation detail or an abstraction leak. It's a part of the interface.
> Since objects are values in C++, you need to know the size of things much more often.
Pretty sure everything is a value in ML and Haskell, and I don't recall every having to worry about the size of anything when using those languages. C++ programmers tend to wrongly conflate “value” with “a physical copy of the value”. It's better than what you get in Java (no user-defined values at all!), but it still leaves a lot to be desired.
- humanrebar 10y ago> Pretty sure everything is a value in ML and Haskell, That's a good point. I guess it's the combination of value semantics and manual memory management. I'll try to keep that in mind in the future. > When you care about ownership, “who frees this object” isn't an implementation detail or an abstraction leak. It's a part of the interface. Exactly. But even more than that, references that don't extend the lifetimes of objects (like native pointers and references) are simple to create and are in many ways the default type of reference in C++. At any rate, 'this message queue only works with types that are easy to copy' is not generally a prominent part of the documentation in C++, if it's present at all.
- gpderetta 10y agoIn C++, a well designed generic component will document the concept requirements of its type parameters. No idea what 'easy to copy' means, but if it is just means that T has a copy constructor, then the requirement would simply stated as "requires: T models CopyConstructible" (which are well defined terms of art). Hopefully one day C++ will allow defining these contracts in code. Note that Concepts carry both syntactic and semantic requirements. edit: typos
- humanrebar 10y ago"Easy to copy" means it makes sense to copy as needed in a given context. Large vectors of strings adhere to the CopyConstructible concept, but we don't generally recommend copying those around. Which brings up a good point. The concepts proposal exists because there are implicit (though hopefully documented) contracts that are either unenforced or enforced in arcane ways (large amounts of error spew obscuring fairly simple violations, such as a missing copy constructor). Anyway, I was trying to point out that there are many language-legal designs we can conceive that force design decisions and other entanglements on other pieces of code. It just so happens that C++ has much more flexibility than many languages, so it gives new opportunities to make those mistakes. I was pointing out that otherwise helpful authors aren't aware of the extra pitfalls, so they tend not to point them out very clearly. As a result, for example, we see a lot of Java-like C++ that basically assumes the rest of the code can and should be structured similarly. Even something as seemingly innocuous as using shared_ptr as a method parameter can cause unintended issues in other code.
- cbsmith 10y ago> But even more than that, references that don't extend the lifetimes of objects (like native pointers and references) are simple to create and are in many ways the default type of reference in C++. C++ has a lot of cases of defaults that one tends not to use all that much (because it tends to default to maximal efficiency). Raw pointers would be a good example. Those are generally frowned upon. On the other hand, references are encouraged and have pretty clear semantics around ownership. > At any rate, 'this message queue only works with types that are easy to copy' is not generally a prominent part of the documentation in C++, if it's present at all. Really? That's a very prominent part of say... the STL's documentation.
- humanrebar 10y agoEven the documentation of vector describes what it does and few implications. It doesn't warn you that vectors of raw pointers are bad parameter types, for example. It does talk about iterator invalidation, but it doesn't really educate us about how that affects our designs. That's not to criticize vector, but to point out that C++ had especially nuanced implications if loosely coupled design is a concern.
- cbsmith 10y ago> It doesn't warn you that vectors of raw pointers are bad parameter types, for example. Vectors of raw pointers function very effectively, they just have all the problems intrinsic with the use of raw pointers. I'm not sure I'd blame the vector documentation for that... > It does talk about iterator invalidation, but it doesn't really educate us about how that affects our designs. Design implications are a subtle thing that you can write entire books about. I think failing to fully capture those implications in the API documentation is more than understandable and far from unusual. For example, Java's containers have similar issues with iterator invalidation, and similarly don't have documentation on all the design implications.
- catnaroek 10y ago> But even more than that, references that don't extend the lifetimes of objects (like native pointers and references) are simple to create and are in many ways the default type of reference in C++. There's nothing wrong with references that don't extend the lifetime of objects per se. Rust gets it right: the compiler checks that non-owning references don't outlive what they refer to. > At any rate, 'this message queue only works with types that are easy to copy' is not generally a prominent part of the documentation in C++, if it's present at all. I would expect it to be in the documentation. It could be phrased as follows: “This message queue only works with types with trivial copy constructors both for them and the types of their member variables, transitively”. Again, Rust gets it right: a generic can be parameterized by a type implementing the `Copy` trait. `MsgQueue<T: Copy>` tells you, in less than 20 characters, the same information as the preceding English tl;dr.