3 ms·
I doubt it's really safer at that point. You could use a few vectors or other container objects, which is a tradeoff - it gets a little bit more comfortable to
by jstimpfle 6y ago
I doubt it's really safer at that point.
You could use a few vectors or other container objects, which is a tradeoff - it gets a little bit more comfortable to spot/debug OOB issues (but valgrind and sorts can also help with the occasional problem). In exchange you are required to structure your data and code in a particular way to use these structures, which is a drawback. Another drawback is slower compile times (significantly so with std:: containers -- don't have a lot of experience with hand rolling C++ abstractions).
I often prefer having globally allocated (dynamic) arrays, which are unproblematic with respect to OOB or memory/allocation safety. I use a simple macro to wrap allocation of arrays to remove the boilerplate. It becomes like "realloc_array(pptr, FooType, 42)" or even "realloc_array(pptr, 42)". Local allocations are more often not easily dealt with using Memory Arenas, which is superior to alloc/free in constructors/destructor.
I even prefer using plain pointers with separate size variables for dynamic arrays. That's because "size :: array" isn't a 1::1 relationship. More than 50% of the time, I have more than one array that applies to the same size variable. Sometimes, there are multiple index/size pairs that apply to a single (or multiple) arrays.
I prefer staying with C because it keeps me focused. Sure, sometimes I wish for the occasional fancy feature, but then taking the time to think about a clean approach that solves the problem with limited features often benefits code quality and readability.
- jcelerier 6y ago> I doubt it's really safer at that point. the number of bugs that the compiler has saved me by e.g. having a simple Id<T> type tag instead of ints as used by every C library under the sun is absurd.
- jstimpfle 6y agoI don't know, I've tried approaches like that, even played with writing a few C++ helper functions, and even started a compiler with the goal of exploring ideas like this. How do you go about Id<T>? The way I see that something like this can work out and give small advantages is that T would be an abstract type (a phantom or tag type, or whatever C++ guys are calling it). And all arrays that are meant to be indexed using Id<T> (while the array element types could be whatever) would depend on this type and have to be implemented using a special wrapped array type with overloaded operator[]. I don't know, this might come with many disadvantages. All the stuff goes out the roof when you're now dealing with start indices + slices, i.e. doing "pointer" arithmetics. My general feeling is that this Id<T> approach might show problems similar to the idea of using typed units, like wanting to prevent the expression "1W + 3s" but then making it terribly cumbersome to do real work, e.g. "1W * 3s" which would be perfectly valid. In one C project I resorted to using about 20-30 typedefs like: typedef int Expr; typedef int Symbol; etc. And I used these typedef names in function signatures. Variables also were named like expr, parentExpr, symbol, etc. It worked wonderfully. I had maybe 1 mistake where I submitted the wrong "type" in 6 months. And I'm someone who makes a lot of stupid mistakes.
- jcelerier 6y ago> How do you go about Id<T>? The way I see that something like this can work out and give small advantages is that T would be an abstract type (a phantom or tag type, or whatever C++ guys are calling it). in a very simplified way: template<typename T> struct Id { int value; }; template<typename T> struct Identifiable { Id<T> id; }; struct MyEntity : Identifiable<MyEntity> { string name; void foobar(); }; > And all arrays that are meant to be indexed using Id<T> (while the array element types could be whatever) would depend on this type and have to be implemented using a special wrapped array type with overloaded operator[]. std::unordered_map<Id<T>, whatever> works fine (or your container of choice... flat_map, boost::multi_index...). > It worked wonderfully. I had maybe 1 mistake where I submitted the wrong "type" in 6 months. well, you're good, I remember when I introduced this in my code base, that caught a dozen bugs almost immediately - and I get prevented by the compiler to introduce more every couple months.
- bregma 6y agoRAII has saved my bacon many times.
- jstimpfle 6y agoRAII has given my programs really fat chubby bacons many times. And made them harder to understand.
- otabdeveloper4 6y ago> And made them harder to understand. Sorry to be blunt, but I'm sure that C++ isn't the problem here.
- jstimpfle 6y agoNo problem, I see you had to be blunt. And thanks for your insightful comment!