Not having RAII is precisely the reason I prefer C over C++ or Rust. I WANT to be able to separate allocation from initialization.
I'm currently working with Arduino code and the API is a mess. Everything has a second set of manual constructor/destructor, which bypasses type-safety entirely. All only to shoehorn having existing, but uninitialized objects into C++.
With Rust there are ways to do that on embedded (no heap). A wrapper StaticCell holds the allocation, then when you are ready you intialise it with the inner value. From then on work with a mut reference to the inner value. Being a bit verbose is the main downside AFAIK.
Yes and that is another large part of work for me, but this pattern is mandated by the Arduino API themself and I don't see another way given the specification and the design of C++, short of switching over to C.
Both C++ and Rust allow that? Having niche behaviour not be the default makes sense, but both know it's needed and therefore allow it?
(C++ lets you malloc and then placement new (just casting the pointer like C does is UB, but it's being fixed for trivial types) and Rust has both plain alloc and Box<MaybeUninit<T>>)
There are a lot of other reasons not to use them, but yours is a made up strawman.
This isn't what people are talking about, you aren't understanding the problem
With RAII you need to leave everything in an initialized state unless you are being very very careful - which is why MaybeUninit is always surrounded by unsafe
{
Foo f;
}
f must be initialized here, it cannot be left uninitialized
std::vector<T> my_vector(10000);
EVERY element in my_vector must be initialized here, they cannot be left uninitialized, there is no workaround
Even if I just want a std::vector<uint8_t> to use as a buffer, I can't - I need to manually malloc with `(uint8_t)malloc(sizeof(uint8_t)*10000)` and fill that
So what if the API I'm providing needs a std::vector? well, I guess i'm eating the cost of initializing 10000 objects, pull them into cache + thrash them out just to do it all again when I memcpy into it
This is just one example of many
another one:
with raii you need copy construction, operator=, move construction, move operator=. If you have a generic T, then using `=` on T might allocate a huge amount of memory, free a huge amount of memory, or none of the above. in c++ it could execute arbitrary code
If you haven't actually used a language without RAII for an extended period of time then you just shouldn't bother commenting. RAII very clearly has its downsides, you should be able to at least reason about the tradeoffs without assuming your terrible strawman argument represents the other side of the coin accurately
Yes, that's heap allocation. I'm talking about automatic allocation, by the compiler not getting a pointer from a library function. Like that:
Connection connections[200];
This will call the constructor, which forces me to write the class in a way that has `bool initialized`, and provide a random other method with poses as a second constructor. And now every function has to do a check, whether the constructor was called on the object or I just declare it to be UB and completely loose type safety.
I'm currently working with Arduino code and the API is a mess. Everything has a second set of manual constructor/destructor, which bypasses type-safety entirely. All only to shoehorn having existing, but uninitialized objects into C++.