Ну, я знаю, у многих есть эта проблема выпуска VS. Режим отладки. Я много искал и прошел трассировку стека моей программы и проверил указатели. Однако я не могу понять, почему я получаю ошибку Access Violation в режиме Release, когда моя программа отлично работает в режиме Debug! После нескольких шагов в коде ITK я вдруг увидел, что функция вызывает нарушение доступа. Сначала я представлю свой код, а затем иерархию вызовов, которая вызывает это нарушение прав доступа:
Вот мои определения типов:
//typedef unsigned char PixelType;
const unsigned int dimention = 3;
//STD types
typedef std::vector<std::string> FileNamesContainer;
typedef std::vector<std::string> SeriesUIDContainer;
//ITK Types
typedef itk::DICOMSeriesFileNames NamesGeneratorType;
typedef itk::Image <signed short, dimention> ImageType; //Defining Image Type
typedef itk::ImageSeriesReader<ImageType> ReaderType; //Defining the type of the image series reader
//GDCM Types
typedef itk::GDCMImageIO DICOMImageIOType;
Вот моя функция:
ReaderType::Pointer itkReadDICOM::ReadImages(char *sourceFolderAddress, std::string &seriesUID)
{
std::cout<<"- Getting file names in: "<<sourceFolderAddress<<std::endl;
std::cout<<"- Series ID: "<<seriesUID<<std::endl;
//Creating a pointer to an object of the reader type. ReaderType is defined on top as itk ImageSeriesReader
ReaderType::Pointer reader = ReaderType::New();
//Setting the IO type by creating a dicomIO object from the GDCMImageIO. This will make sure we read DICOM images.
DICOMImageIOType::Pointer dicomIO = DICOMImageIOType::New();
reader->SetImageIO(dicomIO);
//Creating a dicom series name generator. It will generate the name of the dicom series based on the input directory.
NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New();
namesGenerator->SetDirectory(sourceFolderAddress);
//Getting names and passing the names to the reader to read them.
FileNamesContainer fileNames = namesGenerator->GetFileNames(seriesUID);
reader->SetFileNames(fileNames);
std::cout<<"- Reading files ... ";
//Adding a reading progress observer to the reader so we can see how are we reading.
ITKCmdProgressObserver::Pointer progressObserver = ITKCmdProgressObserver::New();
reader->AddObserver(itk::ProgressEvent(), progressObserver);
//Actually reading the files here. If any error happens it will be Printed and the program exists.
try
{
reader->UpdateLargestPossibleRegion();
std::cout<<"Successfully read "<< fileNames.size() <<" file(s)."<<std::endl;
}
catch (itk::ExceptionObject &ex)
{
std::cout<<"Failed."<<std::endl<<"*********************************************************************"<<std::endl;
std::cout<<ex<<std::endl;
std::cout<<"*********************************************************************"<<std::endl;
return 0;
}
return reader;
}
Вызов, вызывающий ошибку:
reader->UpdateLargestPossibleRegion();
Вышеупомянутый вызов функции проходит через эту цепочку вызовов, которые в конечном итоге вызывают ошибку:
1.
this->UpdateOutputInformation(); //void ProcessObject::UpdateLargestPossibleRegion()
2.
this->GenerateOutputInformation(); //void ProcessObject::Update()
3.
reader->UpdateOutputInformation(); //template <class TOutputImage> void ImageSeriesReader<TOutputImage>::GenerateOutputInformation(void)
4.
this->GenerateOutputInformation(); //void ProcessObject::UpdateOutputInformation()
5.
m_ImageIO->SetFileName(m_FileName.c_str());
m_ImageIO->ReadImageInformation(); //template <class TOutputImage, class ConvertPixelTraits> void ImageFileReader<TOutputImage, ConvertPixelTraits> ::GenerateOutputInformation(void)
На шаге 5 первая строка в порядке, а вторая строка вызывает нарушение прав доступа. Это даже не позволяет мне пройти через это. Я использую Visual Studio 2010. Я ценю ваши ответы.
Спасибо Паоло за ваш ответ. Я пробовал несколько вещей параллельно, пока не нашел решение! Я не мог заставить gflags запускать мою программу, но, поскольку у меня было внутреннее чувство, что проблема на самом деле не в коде, я не тратил на это слишком много времени.
В любом случае вот что я сделал и РЕШИТЬ эта проблема:
Я скачал образец с сайта ITK под названием resampleDICOM и скомпилировал его, и у меня возникла та же проблема. Поэтому изначально я думал, что это ошибка ITK. Затем я перекомпилировал ITK в режиме выпуска с отладкой (RelWithDebInfo), чтобы перейти к коду ITK во время отладки в режиме выпуска. К моему удивлению, полностью действительный указатель, связанный с GDCMImageIO :: MetaDataDictionary, внезапно превратился в неверный указатель () без какого-либо кода, влияющего на него. Так что я понял, что где-то должна быть куча коррупции! Я также знал, что то, что вызывает это повреждение, не может быть в моем коде.
Поэтому я прочитал во многих потоках, что смешивание файлов .lib и .dll отладки и выпуска может сделать вещи действительно неприятными. Но я был уверен, что использую ITK-релиз .lib-файлов и .dll-файлов, поскольку проверял их много раз! и я имею в виду MAAANY раз! Я собирался спрыгнуть с балкона и положить конец этому страданию, потому что у меня возникла эта идея, просто чтобы убедиться, что моя программа не использует ничего при отладочной компиляции ITK. Поэтому я изменил имя папки отладки ITK на другое и запустил мою программу в режиме выпуска и вдруг:
ITKCommon.dll is missing!
Несмотря на то, что я установил все папки и все настройки в Visual Studio для использования папки выпуска, моя программа использовала ITKCommon.dll во время выполнения из папки отладки. Поэтому я скопировал файл ITKCommon.dll из сборки релиза в папку релиза и вуаля! Моя программа работала как шарм.
Попробуйте использовать GFLAGS (доступно в инструментах отладки WinSDK) или appverifier (я думаю, что это также в winsdk).
При включении gflag в вашем приложении (в режиме отладки) оно обнаружит все неприятности, которые происходят с памятью, и повысит точку останова, как только случится что-то плохое