I think another misconception is that you need pointers at all. Smart pointers are still pointers. Its better to use value semantic all the way when you can. And you usually can. Why place something on the heap if it can live on the stack?
I think another misconception is that you need pointers at all. Smart pointers are still pointers. Its better to use value semantic all the way when you can. And you usually can. Why place something on the heap if it can live on the stack?
>Well said! Dynamic memory allocation is a really big performance hit
Unless its such a large huge object that stackoverflow is a possibility I cant imagine why would one do that.
So, if you want to allocate N objects, where N is not known at compile time, (I think) you have to use heap allocation anyway. Normally I just use vector<>, and call reserve() if I feel like extra performance-y. Sure, it's much slower than C99-style variable length arrays, but 99% of the time it's still fast enough.
More importantly, it plays nice with other C++ functionalities. For example, zero-copy construction using emplace_back() inside a for loop. (And if you throw an exception in the middle you're guaranteed that destructors are called exactly for those that are already constructed.)
VLAs are not part of the standard but GCC supports them. Clang however does not, at least not without a compiler flag I think.
And, yeah its disappointing C99 arrays did not make it to C++, one can use alloca to live a little dangerously, better to wrap it so that it allocates on the heap only if more than a certain size has been asked for. Too bad there is no portable way to find out how much stack space does the current process still have. There should have been a system call for that.
To be sure, though, being able to make proper value types is a strength of C++. Also we should point out most non-trivial value types make extensive (and necessary!) use of the heap under the hood (eg string, vector)
For instance this does not do any expensive copies:
std::string getStr() { auto huge_str = getDatabaseDump(); return huge_str; }
void readStr(const std::string& str ){ //read str.. }
int main() { auto str = getStr(); readStr(str); }
We as users of that library type should not additionally put that object on the heap though, if we dont have too. Its simply unnecessary.
Its makes for one extra unnecessary pointer indirection, it adds unnecessary reference counting if using smart pointers, or unnecessary manual memory management if we use raw pointers. It complicates the interface for our functions if we have to wrap types in smart pointers.
As for c++ references. Yes that's true. As I understand it they are implemented as pointers internally by compilers. But in important ways they behave more like values, rather than pointers. As in if you copy or assign to them, they copy or assign the value (not the pointer). If you take their address they give the address of the value (not the pointer). Because of this there are not as many pitfalls to using them as there is with pointers. I see them mostly just as aliases for values.
In the example above I could have passed the string by value (instead of by reference) to the function. It would still not have done a expensive copy, because of copy elision optimisation. I probably should have done that. It looks a bit funny, and takes some getting used too.
Relevant: https://web.archive.org/web/20140205194657/http://cpp-next.c...
The problem with copy elision is that it's an optional compiler optimization and you have to check if the compiler applies it to you particular piece of code. That doesn't scale for large code bases (nor for small ones imho).