C++ STL Set:找不到()最后插入的元素

Luk*_*eFu 1 c++ stl

我正在编写一个应用程序,在该应用程序中我使用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() );
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到的输出是:

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]
Run Code Online (Sandbox Code Playgroud)

**编辑我有点难过,我必须添加这个.但正如我之前提到的,这是一个示例应用程序,它从较大的应用程序的不同部分提取,以显示我收到的故障.

它意味着在用堆分配的指针填充的集合上调用set :: find的单元测试.如果你对所有的new()都有问题,我会接受有关如何使用堆分配的指针神奇地填充集合而不使用它们的建议.否则评论"太多新的()调用"只会让你看起来很傻.

请关注正在发生的实际问题(现已解决).谢谢.

***编辑

也许我应该把这些放在原来的问题中.但是我希望有更多关注find()的问题(或者因为它结果是更像strcmp而不是更少的fileinfo_comparator函数),然后是复制粘贴PoC单元测试的代码审查.

以下是有关完整应用程序本身代码的一些要点.

  • FileInfo包含大量数据和文件名.它包含SHA1总和,文件大小,模态时间,最后编辑时的系统状态等.我已经删除了这篇文章的代码必须.它以这种形式违反了规则3(感谢@Martin York.请参阅wiki链接的评论).
  • 最初选择使用char*over std :: string是因为使用了接受char*的3rd_party API.该应用程序从那时起逐渐发展.改变这一点不是一种选择.
  • FileInfo中的数据从系统上的命名管道进行轮询,并存储在Singleton中,以便跨多个线程进行访问.(如果我没有在堆上分配,我会有范围问题)
  • 我选择在Set中存储指针,因为FileInfo对象很大并且不断地从Set中添加/删除.我决定指针比总是将大型结构复制到Set中更好.
  • 我的析构函数中的if语句是不必要的,并且是我正在跟踪的问题的调试中的遗留工件.它应该被拔出,因为它是不需要的.

Nik*_*sov 10

你的比较函数是错误的 - 它返回bool,而不是整数strcmp(3).return语句应该是这样的:

return strcmp( f1->getFile(), f2->getFile() ) < 0;
Run Code Online (Sandbox Code Playgroud)

看看这里.

另外,出于好奇,为什么不使用std::set<std::string>呢?STL实际上具有不错的默认值,并使您免于大量的手动内存管理.