You won’t need std::make_unique in this case. You use make_unique to invoke an object’s constructor. In your case you let File::createOutputStream() do the work of constructing the object as it returns a pointer to a new instance of the output stream and now you are responsible to take over the ownership.
To do this with a unique ptr you can just pass in the raw pointer to the unique ptr’s constructor or reassign the raw pointer to the unique ptr via reset. So it would be:
What you did above was creating a unique ptr that does not hold the FileOutputStream object itself but a raw pointer to a FileOutputStream. When your unique ptr goes out of scope it will delete the raw pointer it holds but not the actual instance the pointer points to and in the end you’ll leak memory
Yeah, sorry for the quick reply. Returning by std::unique_ptr is definitely the best way to do this, I was just trying to illustrate how to scope correctly in if statements if you are dealing with legacy APIs.
Oh wait you are right, that was a bit quick. @dave96’s is the correct way. Side note, the JUCE team announced to update the API so that functions like that will return unique ptrs instead of raw pointers and the code might then read like
if (auto p_os = outf.createOutputStream())
mf.writeTo (*p_os, 0);
It automatically infers the type of the pointer, so that you don’t have to explicitly mention it (i.e. there’s fewer chances to make type conversion errors). It would simplify this situation like so:
if (auto ptr = rawToUnique (outf.createOutputStream()))
mv.writeTo (*ptr, 0);
The only gotcha is that if you accidentally pass a pointer-to-array instead of a pointer-to-element, the unique_ptr destructor will call delete instead of delete[], but this is a problem with ScopedPointer too afaik.
I can’t say I enjoyed replacing ScopedPointer with std::unique_ptr, it is more verbose, and the error messages of the compiler are longer and more complicated to read when you use std::make_unique. Changing existing code that uses ScopedPointer with std::unique_ptr stuff requires a lot of small changes, and at the end the code is just longer and uglier, I feel. So after replacing half of the ScopedPointers in my code with std::unique_ptr, I rolled back everything and decided to use something that is between them, and requires just a simple search and replace for “ScopedPointer”:
/**
a std::unique_ptr<T> enriched with an implicit T* conversion , works as a convenient replacement
for the deprecated juce ScopedPointer.
*/
template <typename T>
class Owned : public std::unique_ptr<T> {
public:
Owned() {}
Owned(T *p) : std::unique_ptr<T>(p) {}
operator T*() const { return this->get(); }
};