【问题标题】:Max_element with boost directory_iterator带有 boost directory_iterator 的 max_element
【发布时间】:2013-07-30 12:57:17
【问题描述】:

我正在使用 boost 的文件系统和 std::max_element() 在给定目录中查找名称最长的文件:

#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;

bool size_comp( directory_entry de1, directory_entry de2  )
{
    return de1.path().string().size() < de2.path().string().size(); 
}

int main(int argc, char* argv[])
{
    path p (argv[1]);   // p is a path to a directory

    directory_iterator itr (p); 
    directory_iterator itr_end; 
    directory_iterator itr_max=::max_element(itr,itr_end,size_comp);
    int max_size = itr_max->path().string().size();
    cout << "Longest file name: " << itr_max->path() << " has " 
         << max_size << " characters" << endl; 
    return 0;
}

对于包含文件 cat.dat、mouse.dat、elephant.dat 的目录 Animals,输出为:

Longest file name: Animals/mouse.dat has 17 characters

这既不是最长也不是最短的文件名。上面的代码有什么问题?

【问题讨论】:

    标签: c++ boost iterator


    【解决方案1】:

    boost::filesystem::directory_iterator 共享状态。该实现声明该实现由boost::shared_ptr 管理,以允许 InputIterators 所需的浅拷贝语义。因此,当std::max_element 等算法迭代[first,last) 时,结果迭代器会随着first 的每个增量而间接修改,因为结果迭代器将与first 共享状态。

    要解决此问题,请考虑在整个算法中存储boost::filesystem::directory_entry。例如,可以从directory_iterator 范围构造std::vector&lt;directory_entry&gt;,然后将向量传递给std::max_element。或者,手动编写算法可能更容易。

    这是一个完整的例子,展示了这两种方法,在当前目录上运行。

    #include <algorithm> // std::copy, std::max_element
    #include <iterator>  // std::back_inserter
    #include <iostream>  // std::cout, std::endl
    #include <vector>
    #include <utility>   // std::make_pair
    
    #include <boost/filesystem.hpp>
    #include <boost/foreach.hpp>
    
    namespace fs = boost::filesystem;
    
    bool size_comp(const fs::directory_entry& lhs,
                   const fs::directory_entry& rhs)
    {
      return lhs.path().string().size() < rhs.path().string().size();
    }
    
    /// @brief Finds max by copying all directory entries.
    fs::directory_entry max_full_copy(
      fs::directory_iterator first,
      fs::directory_iterator last)
    {
      // Extract directory_entries from directory_iteartor.
      std::vector<fs::directory_entry> entries;
      std::copy(first, last, std::back_inserter(entries));
      // Find max element.
      return *std::max_element(entries.begin(), entries.end(), &size_comp);
    }
    
    /// @brief Finds max by only storing a copy of the max entry.
    fs::directory_entry max_single_copy(
      fs::directory_iterator first,
      fs::directory_iterator last)
    {
      fs::directory_entry result;
      BOOST_FOREACH(fs::directory_entry& current, std::make_pair(first, last))
      {
        if (size_comp(result, current))
          result = current;
      }
      return result;
    }
    
    int main()
    {
      std::cout << max_full_copy(fs::directory_iterator("."),
                                 fs::directory_iterator()) << "\n"
                << max_single_copy(fs::directory_iterator("."),
                                   fs::directory_iterator()) << std::endl;
    }
    

    还有一个带有输出的示例:

    [tsansbury@localhost tmp]$ ls
    文件_四个文件_一个文件_三个文件_两个
    [tsansbury@localhost tmp]$ ../a.out
    “./file_three”
    "./file_three"

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-17
      • 2013-03-21
      • 2013-04-25
      • 1970-01-01
      相关资源
      最近更新 更多