C++ Constructors, Memory, and Lifetimes
erikmcclure.com
erikmcclure.com
It is unfortunate that many learning resources don't show modern C++ so the language is perceived worse than it is and also more bugs are written, than is necessary.
A rule of thumb: if your function doesn't have a return type, consider that your design maybe wrong in some way.
Note: Any negative reactions to smart pointers on my side may be fueled by a disturbing amount of cargo culting that I had to witness since their inclusion in the standard.
By whom?
> once you fix your programs ownership semantics.
How do you heck know how my programs need fixing?
> Any negative reactions to smart pointers on my side may be fueled by a disturbing amount of cargo culting that I had to witness since their inclusion in the standard.
Any positive reactions to smart pointers on my side may be fuelled by over 30 years experience in using them.
You where the one complaining that sample one liners with void return types where bad code. In my experience shared_ptr is overkill in nearly all trivial code examples, so any one liner containing one is bad code.
> Any positive reactions to smart pointers on my side may be fuelled by over 30 years experience in using them.
Hope you never had to deal with code reviews that suggested putting scoped std::vector uses in shared_ptr s to avoid stack overflows. Or really any code that put objects into smart pointers because it could not because it should.
What's your rationale for that assertion?
Unless I'm reading this wrong (and I'm seeking to be corrected here), it's still fine to use new/delete in certain contexts
struct bla {
int n;
int[] mem;
bla(int n) : n(n), mem(new int[n]{}) {}
~bla() { delete[] mem; }
/* forbid copies (for uniqueness) and moves (to keep this short) */
bla(bla &) = delete;
bla(bla &&) = delete;
bla &operator=(bla &&) = delete;
};
Edit to remove unnecessary null-checkingYet this is also a good example of why you wouldn’t need “delete” or a destructor at all, if “mem” changes to std::unique_ptr<int[]> type.
And even then, you should probably seriously consider std::vector or std::array before trying a unique_ptr array.
int[] mem;
even legal C++?If the [] was after the variable name, because it is the last member, most C++ compilers (GCC, Clang, and MSVC) have a non-standard extension: https://en.wikipedia.org/wiki/Flexible_array_member
a.cpp:2:13: error: expected unqualified-id before '[' token
Also, in modern compilers, parameter variables are mostly passed to functions via registers, with the stack not being involved at all.
Given that this is a C++ thread I'll be pedantic and say that this is really the ABI rather than the compiler as per se.
* even interpreted ones, though the calling conventions and layout are quite different from what is typically written up in the documentation of most compiled languages.
My point was that it's not a question of whether the compiler is modern or not, i.e. I work with an old compiler backend on a modern system and it still gets the ABI correct even if it ends up spilling back to memory too often.
AFAIK (I never looked at an official standard, only at drafts) the standard doesn’t mention the word “stack” at all
A C++ compiler is free to allocate environment frames for every block on the heap.
Whether the "stack" is formalized or not, it's the mental model (and the vocabulary) that's most often used when working with this stuff. I don't think there's anything wrong with the fact that they focused on the forest and not the trees.
As is, it goes into implementation details for block scoped storage, but just posits that new and delete exist without mentioning any detail. That’s unbalanced.
Rereading it, it also assumes you know C well enough to know about malloc, so maybe, just saying “C++ can automatically do stuff when variables go out of scope or when you allocate or free memory. Here’s what it can do…” might be sufficient)
it's not a given
int algo(int*, int n);
int computation(int i, int n) {
int alloc[n];
return algo(alloc, n);
}
on some compilers (Keil for instance afair), alloc will be heap-allocated (and freed when leaving the function) even if it's "automatic storage" (what most people call the stack).Yes, the term "automatic storage" is more accurate here.
Oh my god, please don't write articles about things that you barely understand!
> the exact order that C++ evaluates expressions is extremely complicated and not always defined, ... "
"(Un)defined" and "unspecified" (which order of evaluation of fun-args really is) are two distinct terms in the C++ spec meaning different things, they cannot be used interchangeably.
But I guess it's just yet another thing of "Pedantic assembly-code analysts"...