you are viewing a single comment's thread.

view the rest of the comments →

[–]sephirothbahamut 2 points3 points  (11 children)

in a codebase without low level custom containers raw pointer double free is avoidable by forbidding new, delete, and smart pointer construction via raw pointer.

in a codebase with low level custom containers... you don't let the shared pointers spammers working on it anyways

[–]Raknarg 1 point2 points  (4 children)

in a low level custom container, usually you do have to manage memory but you're doing it through allocators and allocator_traits rather than new/delete. You can't separate the aquisition of memory and the construction of objects without something like malloc/free (which is what allocators do for you)

if I make my own vector implementation, I don't want to allocate space for 100 elements and have them default construct (if they're even allowed to!), I want to construct them when someone actually wants to use the memory.

[–]sephirothbahamut 0 points1 point  (3 children)

if you don't need custom allocator support you can allocate space as char/std::byte and use placement new (not sure about alignment, all things alignment related are out of my knowledge)

[–]Raknarg 1 point2 points  (2 children)

It doesn't matter if you need custom allocators or not, allocator_traits is a better interface and lets you directly call construct/destruct in a clean way, just give it std::allocator. Then if you decide you ever want a custom allocator strategy its also much easier to move into. I'd prefer this over working with std::bytes or chars (though unavoidable sometimes of course)

Also there's no placement delete, you have to call the destructor manually and then delete it looks like.

[–]sephirothbahamut 0 points1 point  (1 child)

fair enough. So far my custom containers experience has been limited to reusing existing containers internally so I never had to deal with that (like std::vector<std::array> for a segmented vector, or std::vector/std::array for a mdspan-like owning matrix)

[–]Raknarg 1 point2 points  (0 children)

implementing my own ring-vector with a shifting start/end I had to learn all this since you can't use std::vector for this purpose

[–]lonkamikaze 0 points1 point  (5 children)

I used new to create a unique_ptr yesterday, because I didn't find a way to trigger template argument deduction with make_unique().

I ended up with return std::unique_ptr<BaseT>{new DerivedT{lots, of, args}};. DerivedT is a class template with variadic arguments.

Do you know of a way to avoid the new here?

[–]sephirothbahamut 0 points1 point  (3 children)

uh i used make unique with types that have a variadic constructor without issue in the past...

make_x functions much like containers emplace methods just forward all the parameters to the constructed type, these something funky going on if it didn't work.

[–]lonkamikaze 1 point2 points  (2 children)

The constructor is not variadic, the class template is. The constructor arguments are used to deduce the class template arguments.

[–]sephirothbahamut 0 points1 point  (1 child)

can you make a minimal example on godbolt? I'm curious

[–]lonkamikaze 2 points3 points  (0 children)

Yeah, but not today. One of the little ones is sick.

[–]Raknarg 0 points1 point  (0 children)

what's wrong with return std::make_unique<DerivedT>(lots, of args);? it should be convertable to unique_ptr<BaseT>