diff --git a/src/Audacity.h b/src/Audacity.h index f0618e187..c2b4523a2 100644 --- a/src/Audacity.h +++ b/src/Audacity.h @@ -242,4 +242,118 @@ namespace std { } #endif +/* +* template class Maybe +* Can be used for monomorphic objects that are stack-allocable, but only conditionally constructed. +* You might also use it as a member. +* Initialize with create(), then use like a smart pointer, +* with *, ->, get(), reset(), or in if() +*/ + +template +class Maybe { +public: + + // Construct as NULL + Maybe() {} + + // Supply the copy and move, so you might use this as a class member too + Maybe(const Maybe &that) + { + if (that.get()) + create(*that); + } + + Maybe& operator= (const Maybe &that) + { + if (this != &that) { + if (that.get()) + create(*that); + else + reset(); + } + return *this; + } + + Maybe(Maybe &&that) + { + if (that.get()) + create(::std::move(*that)); + } + + Maybe& operator= (Maybe &&that) + { + if (this != &that) { + if (that.get()) + create(::std::move(*that)); + else + reset(); + } + return *this; + } + + // Make an object in the buffer, passing constructor arguments, + // but destroying any previous object first + // Note that if constructor throws, we remain in a consistent + // NULL state -- giving exception safety but only weakly + // (previous value was lost if present) + template + void create(Args... args) + { + // Lose any old value + reset(); + // Create new value + pp = safenew(address()) X( std::forward(args)... ); + } + + // Destroy any object that was built in it + ~Maybe() + { + reset(); + } + + // Pointer-like operators + + // Dereference, with the usual bad consequences if NULL + X &operator* () const + { + return *pp; + } + + X *operator-> () const + { + return pp; + } + + X* get() const + { + return pp; + } + + void reset() + { + if (pp) + pp->~X(), pp = nullptr; + } + + // So you can say if(ptr) + explicit operator bool() const + { + return pp != nullptr; + } + +private: + X* address() + { + return reinterpret_cast(&storage); + } + + // Data + typename ::std::aligned_storage< + sizeof(X) + // , alignof(X) // Not here yet in all compilers + >::type storage{}; + X* pp{ nullptr }; +}; + #endif // __AUDACITY_H__ diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp index 954e18936..7c1739f9a 100644 --- a/src/AudacityApp.cpp +++ b/src/AudacityApp.cpp @@ -317,7 +317,7 @@ void QuitAudacity(bool bForce) AudacityProject::DeleteAllProjectsDeleteLock(); //remove our logger - delete wxLog::SetActiveTarget(NULL); + std::unique_ptr{ wxLog::SetActiveTarget(NULL) }; // DELETE if (bForce) { @@ -1147,7 +1147,7 @@ bool AudacityApp::OnInit() // Ensure we have an event loop during initialization wxEventLoopGuarantor eventLoop; - delete wxLog::SetActiveTarget(new AudacityLogger); + std::unique_ptr < wxLog > { wxLog::SetActiveTarget(new AudacityLogger) }; // DELETE mLocale = NULL; diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index 4071694f1..9c6cf22c7 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -1343,72 +1343,67 @@ bool AudioIO::StartPortAudioStream(double sampleRate, mNumPlaybackChannels = numPlaybackChannels; mNumCaptureChannels = numCaptureChannels; - PaStreamParameters *playbackParameters = NULL; - PaStreamParameters *captureParameters = NULL; + bool usePlayback = false, useCapture = false; + PaStreamParameters playbackParameters{}; + PaStreamParameters captureParameters{}; double latencyDuration = DEFAULT_LATENCY_DURATION; gPrefs->Read(wxT("/AudioIO/LatencyDuration"), &latencyDuration); if( numPlaybackChannels > 0) { - playbackParameters = new PaStreamParameters; + usePlayback = true; + // this sets the device index to whatever is "right" based on preferences, // then defaults - playbackParameters->device = getPlayDevIndex(); + playbackParameters.device = getPlayDevIndex(); const PaDeviceInfo *playbackDeviceInfo; - playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters->device ); + playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters.device ); if( playbackDeviceInfo == NULL ) - { - delete playbackParameters; return false; - } // regardless of source formats, we always mix to float - playbackParameters->sampleFormat = paFloat32; - playbackParameters->hostApiSpecificStreamInfo = NULL; - playbackParameters->channelCount = mNumPlaybackChannels; + playbackParameters.sampleFormat = paFloat32; + playbackParameters.hostApiSpecificStreamInfo = NULL; + playbackParameters.channelCount = mNumPlaybackChannels; if (mSoftwarePlaythrough) - playbackParameters->suggestedLatency = + playbackParameters.suggestedLatency = playbackDeviceInfo->defaultLowOutputLatency; else - playbackParameters->suggestedLatency = latencyDuration/1000.0; + playbackParameters.suggestedLatency = latencyDuration/1000.0; mOutputMeter = mOwningProject->GetPlaybackMeter(); } if( numCaptureChannels > 0) { + useCapture = true; mCaptureFormat = captureFormat; - captureParameters = new PaStreamParameters; const PaDeviceInfo *captureDeviceInfo; // retrieve the index of the device set in the prefs, or a sensible // default if it isn't set/valid - captureParameters->device = getRecordDevIndex(); + captureParameters.device = getRecordDevIndex(); - captureDeviceInfo = Pa_GetDeviceInfo( captureParameters->device ); + captureDeviceInfo = Pa_GetDeviceInfo( captureParameters.device ); if( captureDeviceInfo == NULL ) - { - delete captureParameters; - delete playbackParameters; return false; - } - captureParameters->sampleFormat = + captureParameters.sampleFormat = AudacityToPortAudioSampleFormat(mCaptureFormat); - captureParameters->hostApiSpecificStreamInfo = NULL; - captureParameters->channelCount = mNumCaptureChannels; + captureParameters.hostApiSpecificStreamInfo = NULL; + captureParameters.channelCount = mNumCaptureChannels; if (mSoftwarePlaythrough) - captureParameters->suggestedLatency = + captureParameters.suggestedLatency = captureDeviceInfo->defaultHighInputLatency; else - captureParameters->suggestedLatency = latencyDuration/1000.0; + captureParameters.suggestedLatency = latencyDuration/1000.0; mInputMeter = mOwningProject->GetCaptureMeter(); } @@ -1429,7 +1424,8 @@ bool AudioIO::StartPortAudioStream(double sampleRate, #endif #endif mLastPaError = Pa_OpenStream( &mPortStreamV19, - captureParameters, playbackParameters, + useCapture ? &captureParameters : NULL, + usePlayback ? &playbackParameters : NULL, mRate, paFramesPerBufferUnspecified, paNoFlag, audacityAudioCallback, NULL ); @@ -1457,10 +1453,6 @@ bool AudioIO::StartPortAudioStream(double sampleRate, } #endif - // these may be null, but deleting a null pointer should never crash. - delete captureParameters; - delete playbackParameters; - return (mLastPaError == paNoError); } diff --git a/src/BlockFile.cpp b/src/BlockFile.cpp index 0d66a2a6d..f4507c376 100644 --- a/src/BlockFile.cpp +++ b/src/BlockFile.cpp @@ -597,25 +597,27 @@ AliasBlockFile::~AliasBlockFile() bool AliasBlockFile::ReadSummary(void *data) { wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb")); - wxLogNull *silence=0; - if(mSilentLog)silence= new wxLogNull(); - if( !summaryFile.IsOpened() ){ + { + Maybe silence{}; + if (mSilentLog) + silence.create(); - // NEW model; we need to return valid data - memset(data,0,(size_t)mSummaryInfo.totalSummaryBytes); - if(silence) delete silence; + if (!summaryFile.IsOpened()){ - // we silence the logging for this operation in this object - // after first occurrence of error; it's already reported and - // spewing at the user will complicate the user's ability to - // deal - mSilentLog=TRUE; - return true; + // NEW model; we need to return valid data + memset(data, 0, (size_t)mSummaryInfo.totalSummaryBytes); - }else mSilentLog=FALSE; // worked properly, any future error is NEW + // we silence the logging for this operation in this object + // after first occurrence of error; it's already reported and + // spewing at the user will complicate the user's ability to + // deal + mSilentLog = TRUE; + return true; - if(silence) delete silence; + } + else mSilentLog = FALSE; // worked properly, any future error is NEW + } int read = summaryFile.Read(data, (size_t)mSummaryInfo.totalSummaryBytes); diff --git a/src/DirManager.cpp b/src/DirManager.cpp index 65374e34e..5e6232db9 100644 --- a/src/DirManager.cpp +++ b/src/DirManager.cpp @@ -197,7 +197,6 @@ static int RecursivelyEnumerate(wxString dirPath, return count; } - static int RecursivelyEnumerateWithProgress(wxString dirPath, wxArrayString& filePathArray, // output: all files in dirPath tree wxString dirspec, @@ -205,19 +204,16 @@ static int RecursivelyEnumerateWithProgress(wxString dirPath, int progress_count, const wxChar* message) { - ProgressDialog *progress = NULL; + Maybe progress{}; if (message) - progress = new ProgressDialog(_("Progress"), message); + progress.create( _("Progress"), message ); int count = RecursivelyEnumerate( dirPath, filePathArray, dirspec, bFiles, bDirs, progress_count, 0, - progress); - - if (progress) - delete progress; + progress.get()); return count; } @@ -291,10 +287,10 @@ static void RecursivelyRemove(wxArrayString& filePathArray, int count, bool bFiles, bool bDirs, const wxChar* message = NULL) { - ProgressDialog *progress = NULL; + Maybe progress{}; if (message) - progress = new ProgressDialog(_("Progress"), message); + progress.create( _("Progress"), message ); for (int i = 0; i < count; i++) { const wxChar *file = filePathArray[i].c_str(); @@ -305,9 +301,6 @@ static void RecursivelyRemove(wxArrayString& filePathArray, int count, if (progress) progress->Update(i, count); } - - if (progress) - delete progress; } diff --git a/src/blockfile/LegacyBlockFile.cpp b/src/blockfile/LegacyBlockFile.cpp index dce1abff7..7e0f959c4 100644 --- a/src/blockfile/LegacyBlockFile.cpp +++ b/src/blockfile/LegacyBlockFile.cpp @@ -69,26 +69,28 @@ void ComputeLegacySummaryInfo(wxFileName fileName, SampleBuffer data(info->frames64K * fields, info->format); - wxLogNull *silence=0; - wxFFile summaryFile(fileName.GetFullPath(), wxT("rb")); int read; - if(Silent)silence= new wxLogNull(); + { + Maybe silence{}; + wxFFile summaryFile(fileName.GetFullPath(), wxT("rb")); + if (Silent) + silence.create(); - if( !summaryFile.IsOpened() ) { - wxLogWarning(wxT("Unable to access summary file %s; substituting silence for remainder of session"), - fileName.GetFullPath().c_str()); + if (!summaryFile.IsOpened()) { + wxLogWarning(wxT("Unable to access summary file %s; substituting silence for remainder of session"), + fileName.GetFullPath().c_str()); - read=info->frames64K * info->bytesPerFrame; - memset(data.ptr(), 0, read); - }else{ - summaryFile.Seek(info->offset64K); - read = summaryFile.Read(data.ptr(), - info->frames64K * - info->bytesPerFrame); + read = info->frames64K * info->bytesPerFrame; + memset(data.ptr(), 0, read); + } + else{ + summaryFile.Seek(info->offset64K); + read = summaryFile.Read(data.ptr(), + info->frames64K * + info->bytesPerFrame); + } } - if(silence) delete silence; - int count = read / info->bytesPerFrame; CopySamples(data.ptr(), info->format, @@ -151,22 +153,23 @@ LegacyBlockFile::~LegacyBlockFile() bool LegacyBlockFile::ReadSummary(void *data) { wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb")); - wxLogNull *silence=0; - if(mSilentLog)silence= new wxLogNull(); + int read; + { + Maybe silence{}; + if (mSilentLog) + silence.create(); - if( !summaryFile.IsOpened() ){ + if (!summaryFile.IsOpened()){ - memset(data,0,(size_t)mSummaryInfo.totalSummaryBytes); + memset(data, 0, (size_t)mSummaryInfo.totalSummaryBytes); - if(silence) delete silence; - mSilentLog=TRUE; + mSilentLog = TRUE; - return true; + return true; + } + + read = summaryFile.Read(data, (size_t)mSummaryInfo.totalSummaryBytes); } - - int read = summaryFile.Read(data, (size_t)mSummaryInfo.totalSummaryBytes); - - if(silence) delete silence; mSilentLog=FALSE; return (read == mSummaryInfo.totalSummaryBytes); @@ -215,19 +218,20 @@ int LegacyBlockFile::ReadData(samplePtr data, sampleFormat format, sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE); } - wxLogNull *silence=0; - if(mSilentLog)silence= new wxLogNull(); + { + Maybe silence{}; + if (mSilentLog) + silence.create(); - if (!sf){ + if (!sf){ - memset(data,0,SAMPLE_SIZE(format)*len); + memset(data, 0, SAMPLE_SIZE(format)*len); - if(silence) delete silence; - mSilentLog=TRUE; + mSilentLog = TRUE; - return len; + return len; + } } - if(silence) delete silence; mSilentLog=FALSE; sf_count_t seekstart = start + diff --git a/src/blockfile/PCMAliasBlockFile.cpp b/src/blockfile/PCMAliasBlockFile.cpp index 2e9a7dd63..0559e8ef6 100644 --- a/src/blockfile/PCMAliasBlockFile.cpp +++ b/src/blockfile/PCMAliasBlockFile.cpp @@ -80,37 +80,37 @@ int PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, return len; } - wxLogNull *silence=0; - if(mSilentAliasLog)silence= new wxLogNull(); - - memset(&info, 0, sizeof(info)); - wxFile f; // will be closed when it goes out of scope SNDFILE *sf = NULL; + { + Maybe silence{}; + if (mSilentAliasLog) + silence.create(); - if (f.Exists(mAliasedFileName.GetFullPath())) { // Don't use Open if file does not exits - if (f.Open(mAliasedFileName.GetFullPath())) { - // Even though there is an sf_open() that takes a filename, use the one that - // takes a file descriptor since wxWidgets can open a file with a Unicode name and - // libsndfile can't (under Windows). - ODManager::LockLibSndFileMutex(); - sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE); - ODManager::UnlockLibSndFileMutex(); + memset(&info, 0, sizeof(info)); + + if (f.Exists(mAliasedFileName.GetFullPath())) { // Don't use Open if file does not exits + if (f.Open(mAliasedFileName.GetFullPath())) { + // Even though there is an sf_open() that takes a filename, use the one that + // takes a file descriptor since wxWidgets can open a file with a Unicode name and + // libsndfile can't (under Windows). + ODManager::LockLibSndFileMutex(); + sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE); + ODManager::UnlockLibSndFileMutex(); + } + } + + if (!sf){ + memset(data, 0, SAMPLE_SIZE(format)*len); + silence.reset(); + mSilentAliasLog = TRUE; + + // Set a marker to display an error message for the silence + if (!wxGetApp().ShouldShowMissingAliasedFileWarning()) + wxGetApp().MarkAliasedFilesMissingWarning(this); + return len; } } - - if (!sf){ - memset(data,0,SAMPLE_SIZE(format)*len); - if(silence) delete silence; - mSilentAliasLog=TRUE; - - // Set a marker to display an error message for the silence - if (!wxGetApp().ShouldShowMissingAliasedFileWarning()) - wxGetApp().MarkAliasedFilesMissingWarning(this); - return len; - } - - if(silence) delete silence; mSilentAliasLog=FALSE; ODManager::LockLibSndFileMutex(); diff --git a/src/blockfile/SimpleBlockFile.cpp b/src/blockfile/SimpleBlockFile.cpp index a0a38eacf..36335c340 100644 --- a/src/blockfile/SimpleBlockFile.cpp +++ b/src/blockfile/SimpleBlockFile.cpp @@ -345,21 +345,21 @@ bool SimpleBlockFile::ReadSummary(void *data) wxFFile file(mFileName.GetFullPath(), wxT("rb")); - wxLogNull *silence=0; - if(mSilentLog)silence= new wxLogNull(); + { + Maybe silence{}; + if (mSilentLog) + silence.create(); - if(!file.IsOpened() ){ + if (!file.IsOpened()){ - memset(data,0,(size_t)mSummaryInfo.totalSummaryBytes); + memset(data, 0, (size_t)mSummaryInfo.totalSummaryBytes); - if(silence) delete silence; - mSilentLog=TRUE; + mSilentLog = TRUE; - return true; + return true; + } } - - if(silence) delete silence; mSilentLog=FALSE; // The offset is just past the au header @@ -400,31 +400,31 @@ int SimpleBlockFile::ReadData(samplePtr data, sampleFormat format, //wxLogDebug("SimpleBlockFile::ReadData(): Reading data from disk."); SF_INFO info; - wxLogNull *silence=0; - if(mSilentLog)silence= new wxLogNull(); - - memset(&info, 0, sizeof(info)); - wxFile f; // will be closed when it goes out of scope SNDFILE *sf = NULL; + { + Maybe silence{}; + if (mSilentLog) + silence.create(); - if (f.Open(mFileName.GetFullPath())) { - // Even though there is an sf_open() that takes a filename, use the one that - // takes a file descriptor since wxWidgets can open a file with a Unicode name and - // libsndfile can't (under Windows). - sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE); + memset(&info, 0, sizeof(info)); + + if (f.Open(mFileName.GetFullPath())) { + // Even though there is an sf_open() that takes a filename, use the one that + // takes a file descriptor since wxWidgets can open a file with a Unicode name and + // libsndfile can't (under Windows). + sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE); + } + + if (!sf) { + + memset(data, 0, SAMPLE_SIZE(format)*len); + + mSilentLog = TRUE; + + return len; + } } - - if (!sf) { - - memset(data,0,SAMPLE_SIZE(format)*len); - - if(silence) delete silence; - mSilentLog=TRUE; - - return len; - } - if(silence) delete silence; mSilentLog=FALSE; sf_seek(sf, start, SEEK_SET); diff --git a/src/effects/VST/VSTEffect.cpp b/src/effects/VST/VSTEffect.cpp index 988aaaf5f..51c8fda17 100644 --- a/src/effects/VST/VSTEffect.cpp +++ b/src/effects/VST/VSTEffect.cpp @@ -456,7 +456,7 @@ bool VSTEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxStrin wxString effectIDs = wxT("0;"); wxStringTokenizer effectTzr(effectIDs, wxT(";")); - wxProgressDialog *progress = NULL; + Maybe progress{}; size_t idCnt = 0; size_t idNdx = 0; @@ -517,16 +517,16 @@ bool VSTEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxStrin idCnt = effectTzr.CountTokens(); if (idCnt > 3) { - progress = new wxProgressDialog(_("Scanning Shell VST"), - wxString::Format(_("Registering %d of %d: %-64.64s"), 0, idCnt, proc.GetName().c_str()), - idCnt, - NULL, - wxPD_APP_MODAL | - wxPD_AUTO_HIDE | - wxPD_CAN_ABORT | - wxPD_ELAPSED_TIME | - wxPD_ESTIMATED_TIME | - wxPD_REMAINING_TIME); + progress.create( _("Scanning Shell VST"), + wxString::Format(_("Registering %d of %d: %-64.64s"), 0, idCnt, proc.GetName().c_str()), + static_cast(idCnt), + nullptr, + wxPD_APP_MODAL | + wxPD_AUTO_HIDE | + wxPD_CAN_ABORT | + wxPD_ELAPSED_TIME | + wxPD_ESTIMATED_TIME | + wxPD_REMAINING_TIME ); progress->Show(); } break; @@ -611,11 +611,6 @@ bool VSTEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxStrin } } - if (progress) - { - delete progress; - } - return valid; } diff --git a/src/import/ImportMP3.cpp b/src/import/ImportMP3.cpp index afb7f8450..034fbdb95 100644 --- a/src/import/ImportMP3.cpp +++ b/src/import/ImportMP3.cpp @@ -213,7 +213,7 @@ int MP3ImportFileHandle::Import(TrackFactory *trackFactory, Track ***outTracks, mPrivateData.file = mFile; mPrivateData.inputBuffer = new unsigned char [INPUT_BUFFER_SIZE]; - mPrivateData.progress = mProgress; + mPrivateData.progress = mProgress.get(); mPrivateData.channels = NULL; mPrivateData.updateResult= eProgressSuccess; mPrivateData.id3checked = false; diff --git a/src/import/ImportPlugin.h b/src/import/ImportPlugin.h index acf44408e..8b506baa0 100644 --- a/src/import/ImportPlugin.h +++ b/src/import/ImportPlugin.h @@ -119,17 +119,12 @@ class ImportFileHandle /* not final */ public: ImportFileHandle(const wxString & filename) : mFilename(filename), - mProgress(NULL) + mProgress{} { } virtual ~ImportFileHandle() { - if (mProgress != NULL) - { - delete mProgress; - mProgress = NULL; - } } // The importer should call this to create the progress dialog and @@ -140,8 +135,7 @@ public: wxString title; title.Printf(_("Importing %s"), GetFileDescription().c_str()); - mProgress = new ProgressDialog(title, - f.GetFullName()); + mProgress.create(title, f.GetFullName()); } // This is similar to GetImporterDescription, but if possible the @@ -170,7 +164,7 @@ public: protected: wxString mFilename; - ProgressDialog *mProgress; + Maybe mProgress; };