我正在编写一个应用程序,在该应用程序中我使用C ++ STL中的Set类。我发现当我查询插入的最后一个元素时,调用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()的问题(或者因为它变得更像strcmp而不是更少的fileinfo_comparator函数),然后是复制粘贴PoC单元测试的代码审查。
以下是有关完整应用程序本身代码的一些要点。
答案 0 :(得分:10)
您的比较函数错误 - 它返回bool
,而不是整数strcmp(3)
。 return语句应该是这样的:
return strcmp( f1->getFile(), f2->getFile() ) < 0;
看看here。
另外,出于好奇,为什么不使用std::set<std::string>
呢? STL实际上具有良好的默认值,并使您免于大量的手动内存管理。
答案 1 :(得分:2)
我认为FileInfo
无法正常工作(至少在std::set
中使用)。要存储在std::set
中,比较函数应返回bool
,表示这两个参数按顺序排列(true
)或按顺序排列(false
)。< / p>
鉴于你的FileInfo
做了什么(模仿std::string
的设计很糟糕),如果没有它,你可能会更好。据我所知,您可以在其位置使用std::string
而不会丢失任何功能。您也没有充分的理由使用大量动态分配(并且泄漏了很多分配的内容)。
#include <set>
#include <iostream>
#include <iterator>
#include <string>
int main() {
char *inputs[] = { "/export/home/lm/profile", "/export/home/lm/shell", "/export/home/lm/mail" };
char *outputs[] = {"Found: ", "Could **not** find: "};
std::set<std::string> MySet(inputs, inputs+3);
for (int i=0; i<3; i++)
std::cout
<< outputs[MySet.find(inputs[i]) == MySet.end()]
<< inputs[i] << "\n";
std::copy(MySet.begin(), MySet.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
编辑:即使(或者真的,尤其是时)FileInfo
更复杂,它也不应该尝试自己重新实现字符串功能。它仍然应该使用std::string
作为文件名,并实现一个适用于它的operator<
:
class FileInfo {
std::string filename;
public:
// ...
bool operator<(FileInfo const &other) const {
return filename < other.filename;
}
FileInfo(char const *name) : filename(name) {}
};
std::ostream &operator(std::ostream &os, FileInfo const &fi) {
return os << fi.filename;
}
int main() {
// std::set<std::string> MySet(inputs, inputs+3);
std:set<FileInfo> MySet(inputs, inputs+3);
// ...
std::copy(MySet.begin(), MySet.end(),
std::ostream_iterator<FileInfo>(std::cout, "\n"));
}
答案 2 :(得分:1)
在你的构造函数中:
FileInfo( const FileInfo & file )
{
setFile( file.getFile() );
}
m_fileName
似乎未初始化。