Я нахожусь в процессе написания приложения, в котором я использую класс Set в C ++ STL.Я обнаружил, что вызов set-> find () всегда кажется неудачным, когда я запрашиваю последний элемент, который я вставил.Однако, если я переберу набор, я смогу увидеть элемент, к которому я первоначально обращался.
Чтобы попытаться понять, что происходит, я создал пример приложения, которое показываеттакое же поведение, которое я наблюдаю.Мой тестовый код размещен ниже.
Для самого приложения мне нужно хранить указатели на объекты в наборе.Это то, что вызывает странное поведение.Или есть оператор, который мне нужно перегрузить в классе, в котором хранится указатель?
Любая помощь будет принята.
#include <stdio.h>
#include <set>
using namespace std;
#define MySet set<FileInfo *,bool(*)(const FileInfo *, const FileInfo*)>
class FileInfo
{
public:
FileInfo()
{
m_fileName = 0;
}
FileInfo( const FileInfo & file )
{
setFile( file.getFile() );
}
~FileInfo()
{
if( m_fileName )
{
delete m_fileName;
m_fileName = 0;
}
}
void setFile( const char * file )
{
if( m_fileName )
{
delete m_fileName;
}
m_fileName = new char[ strlen( file ) + 1 ];
strcpy( m_fileName, file );
}
const char * getFile() const
{
return m_fileName;
}
private:
char * m_fileName;
};
bool fileinfo_comparator( const FileInfo * f1, const FileInfo* f2 )
{
if( f1 && ! f2 ) return -1;
if( !f1 && f2 ) return 1;
if( !f1 && !f2 ) return 0;
return strcmp( f1->getFile(), f2->getFile() );
}
void find( MySet *s, FileInfo * value )
{
MySet::iterator iter = s->find( value );
if( iter != s->end() )
{
printf( "Found File[%s] at Item[%p]\n", (*iter)->getFile(), *iter );
}
else
{
printf( "No Item found for File[%s]\n", value->getFile() );
}
}
int main()
{
MySet *theSet = new MySet(fileinfo_comparator);
FileInfo * profile = new FileInfo();
FileInfo * shell = new FileInfo();
FileInfo * mail = new FileInfo();
profile->setFile( "/export/home/lm/profile" );
shell->setFile( "/export/home/lm/shell" );
mail->setFile( "/export/home/lm/mail" );
theSet->insert( profile );
theSet->insert( shell );
theSet->insert( mail );
find( theSet, profile );
FileInfo * newProfile = new FileInfo( *profile );
find( theSet, newProfile );
FileInfo * newMail = new FileInfo( *mail );
find( theSet, newMail );
printf( "\nDisplaying Contents of Set:\n" );
for( MySet::iterator iter = theSet->begin();
iter != theSet->end(); ++iter )
{
printf( "Item [%p] - File [%s]\n", *iter, (*iter)->getFile() );
}
}
Вывод, который я получаю из этого:
Found File[/export/home/lm/profile] at Item[2d458]
Found File[/export/home/lm/profile] at Item[2d458]
No Item found for File[/export/home/lm/mail]
Displaying Contents of Set:
Item [2d478] - File [/export/home/lm/mail]
Item [2d468] - File [/export/home/lm/shell]
Item [2d458] - File [/export/home/lm/profile]
** Править Грустно, что я должен добавить это.Но, как я упоминал ранее, это пример приложения, которое было извлечено из разных частей более крупного приложения для демонстрации сбоя, который я получал.
Он предназначен в качестве модульного теста для вызова set :: find для набора, заполненного указателями, выделенными для кучи.Если у вас есть проблемы со всеми новыми (), я открыт для предложений о том, как волшебным образом заполнить набор указателями, выделенными для кучи, без их использования.В противном случае, комментируя «слишком много вызовов new ()», вы будете выглядеть глупо.
Пожалуйста, обратите внимание на реальную проблему, которая возникла (которая сейчас решена).Спасибо.
*** Редактировать
Возможно, мне следовало бы поставить их в свой оригинальный вопрос.Но я надеялся, что будет уделено больше внимания проблеме с find () (или, как выясняется, функция fileinfo_comparator, которая действует больше как strcmp, чем less), чем к проверке кода модульного теста PoC копирования-вставки.
Вот несколько моментов, касающихся кода в самом полном приложении.
- FileInfo содержит много данных вместе с именем файла.Он содержит суммы SHA1, размер файла, время модификации, состояние системы при последнем редактировании, среди прочего.Я вырезал код из этого поста.Он нарушает Правило 3 в этой форме (Спасибо @Martin York. См. Комментарии к вики-ссылке).
- Использование char * over std :: string изначально было выбрано из-за использования API-интерфейсов 3rd_party, которые принимаютсимвол *.С тех пор приложение развивалось.Изменить это не вариант.
- Данные внутри FileInfo опрашиваются из именованного канала в системе и хранятся в Singleton для доступа ко многим потокам.(У меня возникли бы проблемы с областью действия, если бы я не выделял в куче)
- Я решил хранить указатели в наборе, поскольку объекты FileInfo большие и постоянно добавляются / удаляются из набора.Я решил, что указатели будут лучше, чем всегда копировать большие структуры в Set.
- Оператор if в моем деструкторе не нужен и является артефактом, оставшимся после отладки проблемы, которую я отслеживал.Его нужно вытащить, потому что он не нужен.