Trouble with initialize

I downloaded a sourde code from github that converts images into wavetables, it’s from 3 years ago so i believe something change in the frame work… I’m getting this error:

‘initializing’: cannot convert from ‘std::unique_ptr<juce::FileOutputStream,std::default_deletejuce::FileOutputStream>’ to ‘juce::FileOutputStream *’

this is the line where im getting the error

FileOutputStream *outputStream = outputFile.createOutputStream();

the whole if statement:

       if(fileDialog.browseForFileToSave(true))
        {
            // Pipe audio data to a file
            File outputFile = fileDialog.getResult();
            int size = (int)AudioOutBuffer[0].size();
            AudioSampleBuffer* buffer = new AudioSampleBuffer(2,size);

            buffer->clear();

            CopyAudioToBuffer(buffer);

            WavAudioFormat* WavFile = new WavAudioFormat();

            FileOutputStream *outputStream = outputFile.createOutputStream();

            AudioFormatWriter* streamWriter = WavFile->createWriterFor(outputStream, 44100, 2, 16, NULL, 0);

            streamWriter->writeFromAudioSampleBuffer(*buffer, 0, size);

            delete streamWriter;
            delete buffer;
        }
    }

thanks!!

This is because a in the meantime a lot of functions that returned pointers that the caller must take ownership of changed their signature to return a std::unique_ptr instead of the raw pointer. This is the modern C++ way of managing object lifetime, as you cannot forget to call delete on such objects and create a memory leak this way. Looking at the code above I can see some leaks, which shows that unique ptrs are a good idea, especially for beginners :slightly_smiling_face: The code block above rewritten with those modern approaches would look something like, I’m fan of using auto a lot to avoid long type names

if(fileDialog.browseForFileToSave(true))
{
    // Pipe audio data to a file
    auto outputFile = fileDialog.getResult();
    auto size = static_cast<int> (AudioOutBuffer[0].size());
    // There is no real reason to allocate an audio buffer with new, its a container itself which can safely live on the stack
    AudioSampleBuffer buffer (2, size); 

    buffer.clear();

    // buffer was a pointer before, so dereferencing it here. Better: Modify CopyAudioToBuffer to take a reference instead of a pointer 
    CopyAudioToBuffer (&buffer);

    // Same as with the buffer above, just keep it on the stack
    WavAudioFormat wavFile;

    // File::createOutputStream also changed to return a unique pointer
    auto outputStream = outputFile.createOutputStream();

    // WavAudioFormat::createWriterFor has not been updated yet and returns a raw pointer. We should wrap it in a unique pointer
    // One special thing here: it this function will take ownership of the stream passed in in case it could create a writer.
    // As there is no error checking if creation worked at all this code assumes that it will always create a writer and will always release the stream
    std::unique_ptr<AudioFormatWriter> streamWriter (wavFile.createWriterFor(outputStream.release(), 44100, 2, 16, nullptr, 0));

    streamWriter->writeFromAudioSampleBuffer (buffer, 0, size);

    // When using unique pointers they will delete their content automatically here without calling delete
    }
}
1 Like

If you’re using c++17, you should do:

if( auto t = funcThatReturnsUniquePtr() ) 
{
    //Ok to use t as it holds a valid object
}

Do this for all of those functions in the example above that return unique_ptrs.

2 Likes

That should be possible with c++14 as well, shouldn’t it?

looks like if( init statement ) is a C++17 thing.

https://en.cppreference.com/w/cpp/language/if

The declaration as condition is C++98. What’s new in C++17 is something like

if (auto a = something; a != whatever)

like a for without the iteration expression.

2 Likes