An important extension to this trick is that unique_ptr and shared_ptr are specialized for arrays. So e.g. to allocate a dynamic array of size n, you can do:
auto a = std::make_unique<char[]>(100);
or auto a = std::make_unique<int[3]>(1, 2, 3);
and then use it mostly like an array - a[i] is overloaded and work as expected, for example.The reason why you'd want to do this rather than using std::vector is because you don't get the overhead of overallocation (since vectors distinct capacity and size) and default-initialization of the elements.
With these, it's quite possible to write >100 kLoC of C++ without a single new or delete in sight.
Julia has several cool performance-oriented constructs too: generated functions, loop fusion, JIT compilation (like your static if), and immutables (http://julialang.org/blog/2013/03/efficient-aggregates). It has a lot of potential, but then, so do other performance-oriented languages. It'll be interesting to do comparisons in a few years when the dust has settled a bit.
Fast chain of operations on an array was one of the primary motivations. You can take a look at Blitz++, I believe it was the first library to push that idea. But ET is not limited to numerical operations on an array, you could do query optimization, optimization of string concatenation, essentially any application where deforestation of parse trees have the potential to make things faster.
https://eigen.tuxfamily.org/dox/TopicLazyEvaluation.html
https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenType...
If you limit the scope of your statement adequately enough, I would agree. What ET did was to remove the overhead that conventional style C++ brought to OOP matrix libraries. Fortran and C would beat C++ libraries hands down. So ET pulled C++ up to level 0: what a naïve (but verbose) implementation in, say C, would have got you. It is only after this the real stuff begins, optimizing for cache reuse, common subexpression elimination. Nowadays there are more advanced ET libraries that do this.
> linear algebra computations
To elaborate on this a bit more. We usually encounter two broad kinds of operations. One is of the linear algebraic variety, e.g. mat_vec, mat_mat etc. Here ET by itself wont buy you much. Here it is all about cach re-use. The other kind of operations are those chained operations (some times these are called array operations, as opposed to matrix or linear algebraic operations), it is here that ET will show its strength. A high performance library in C++ would typically use ET for these and fall back to BLAS for the former.
My experience... sometimes I have to pass through multiple reference frames to get to the correct affine transformation. I have three options: manually derive the transform (only works for a finite number of well understood transformations), waste BLAS ops on transform concatenation, or let expression templates fold numerical operations to the solution (often with numerical precision benefits btw).
Though 99/100 times it allows me to write the code I mean rather than the the syntax that is necessary. Of course concatenation of transforms explicitly can be equivalent in FLOPS... as long as there are no redundant calls to transcendental functions or vector operations which can be folded for better cache coherency.
> computation boils down to the same flops either way?
same number of operations, yes possibly, but that carries almost no weight at all. Write a straight 3 nested for loop for a matrix multiply and then right another one with some thoughts on cache re-use. The latter will beat the former by an order of magnitude if not two. The situation is a bit better now thanks to 'smart enough compilers'.
If you are working with (b|m)illions of particles or entities which are capable of changing ownership, you will have a hard time in any language. Whether that's the C++ ownership being unclear or the garbage collector defragmenting your memory (just because you don't see the issue doesn't means it's gone in GC languages).
That said, typically I find most algorithms have a computable upper-bound memory constraint and so you just pre-allocate a slab and then objects reference it. You will usually get better cache coherency and less wasted operations/sec. You're left with only a couple pointers you need to delete when you're done with the structure.
As for `functional programming`, it depends on what you're looking for. C++ has two killer features for this, in my opinion; expression templates can seriously improve performance of functional composition (see Eigen3), and compile-time elision of type-dependent code branches (like a static if).
Since I have learned to use `unique_ptr`, `shared_ptr`, `weak_ptr`, (`deferred_ptr`), and to prefer idiomatic accessors like `.at`, `.find`, `.insert` I cannot recall the last time Valgrind was angry at me. I think I end up writing `new` and `delete` maybe once a month(?).
If I was designing widgets or applications with hard to define user interaction, I imagine I would have more complaints to share.