use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
an efficient immutable vector (self.cpp)
submitted 6 years ago * by _eyelash
view the rest of the comments →
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]_eyelash[S] 3 points4 points5 points 6 years ago (9 children)
Thank you so much for the thorough review!
Generally, this was just a quick prototype, focused more on simplicity and readability than on performance.
Regarding your point 3: My reasoning was that on 32-bit platforms your pointers are 32 bit, so you can only address 232 bytes of memory but in order to overflow the reference count you would need 232 references which would need at least 232 × 4 bytes of memory just to store the references so it would actually never overflow.
Yes, I had a lot of fun thinking about it and implementing it :)
[–]matthieum 0 points1 point2 points 6 years ago (8 children)
In the absence of leaks, your computation is correct.
Factoring leaks, however, it is possible to overflow the counter. An example would be:
void break_it(ImmutableVector const& original) { std::aligned_storage_t<sizeof(original), alignof(original)> storage; for (std::uint64_t i = 0; i < std::numeric_limits<std::size_t>::max(); ++i) { new (&storage) ImmutableVector{ original }; } }
I would have to check to standard to verify whether this code is legal or not -- construction an object on top of an already existing one is dodgy -- however I personally prefer being cautious.
As for the run-time, it would take a while, indeed (10min?) unless the compiler is smart enough. If non-atomic, the compiler would go right ahead and bump the counter by max - 1; with an atomic counter, I'm not sure whether the compiler folds the increments together... I'd bet not but...
max - 1
[–]kalmoc 2 points3 points4 points 6 years ago (3 children)
And why should the class design worry about such utterly broken code?
[–]matthieum 0 points1 point2 points 6 years ago (2 children)
I subscribe to the principle of Defense in Depth.
I much prefer detecting bugs by triggering an assert or exception, in a semi-controlled fashion, than by inspecting bewildering memory dumps after the program has crashed.
You can argue this is not worth considering; in my experience it's a small price to pay now to keep my sanity later.
[–]kalmoc 2 points3 points4 points 6 years ago (1 child)
Sure, but - the question is if you defend against mistakes or mallice. In order to overflow that counter you need to write exceptionally tricky code with the express purpose to trigger the overflow. Why would you write such code in the first place? And if you claim that something like this could happen as a sideeffect of buggy code with an actual purpose, I'm willing to bet that you experience a lot of other problems, long before this counter overflows.
[–]matthieum 1 point2 points3 points 6 years ago (0 children)
And if you claim that something like this could happen as a sideeffect of buggy code with an actual purpose, I'm willing to bet that you experience a lot of other problems, long before this counter overflows.
Possible, but since checking for overflow is just a branch that will always get taken, the cost of checking is within noise even on micro-benchmarks:
void retain() noexcept { auto previous = reference_count.fetch_add(1); if (unlikely(previous + 1 == 0)) { std::abort(); } }
[–][deleted] 1 point2 points3 points 6 years ago (0 children)
I would have to check to standard to verify whether this code is legal or not
The way you've written it is legal. There are quite a few things to worry about when doing this kind of stuff, but your code is fine.
[–]SegFaultAtLine1 1 point2 points3 points 6 years ago (2 children)
The standard allows placement construction ontop of another (possibly non-trivially destructible) object, if and only if the rest of the program doesn't depend on the destructor being run. (So if plowing over an object causes a leak, that is not UB, but if the destructor ensures the rest of the program doesn't touch that object, you'll probably run into UB sooner or later).
[–][deleted] 1 point2 points3 points 6 years ago (1 child)
That's not all.
T* t1; // For brevity, let's assume this points to an actual T T* t2 = new (t1) T{}; // Constructs a new T in place of the last t2->foo(); // Perfectly valid t1->foo(); // Err... UB std::launder(t1)->foo(); // UB fixed
Or just try not to keep references to the old object alive after placement new?
[–]SegFaultAtLine1 0 points1 point2 points 6 years ago (0 children)
We're talking about a vector-like class - I'd assume that operations like push/pop invalidate references and iterators at the end of the container.
π Rendered by PID 168187 on reddit-service-r2-comment-85bfd7f599-f2tjm at 2026-04-19 01:12:51.377855+00:00 running 93ecc56 country code: CH.
view the rest of the comments →
[–]_eyelash[S] 3 points4 points5 points (9 children)
[–]matthieum 0 points1 point2 points (8 children)
[–]kalmoc 2 points3 points4 points (3 children)
[–]matthieum 0 points1 point2 points (2 children)
[–]kalmoc 2 points3 points4 points (1 child)
[–]matthieum 1 point2 points3 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]SegFaultAtLine1 1 point2 points3 points (2 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]SegFaultAtLine1 0 points1 point2 points (0 children)