freeing C memory automatically using `std::unique_ptr` and `std::shared_ptr`