调试错误R6010 - 已调用abort()

时间:2015-02-15 15:34:31

标签: c++ boost filesystems

我正在编写一个程序,输出它所在文件夹中所有文件的名称,如果其中两个文件具有相同的大小,则只输出一个。请注意,我是升级库的新手,而不是经验丰富的程序员。

以下是我的想法:

#include <boost/filesystem.hpp>      
#include <iostream>
#include<string>
#include<cstdio>
using namespace std;
void files(string a = ".")
{
bool check = 1;
boost::filesystem::directory_iterator iterator(a);

for (; iterator != boost::filesystem::directory_iterator(); ++iterator)
{

    if (is_directory(iterator->path()))
    {
        files(iterator->path().string());
    }
    else
    {
        boost::filesystem::directory_iterator iterator2(a);
        iterator2 = iterator;
        if (iterator != boost::filesystem::directory_iterator())
        {
            iterator2++;
        }
        for (; iterator2 != boost::filesystem::directory_iterator(); ++iterator2)
        {
            if (file_size(iterator->path()) == file_size(iterator2->path()))
            {
                check = 0;
            }
        }
    }
    if (check == 1)
    {

        cout << (iterator->path().filename()) << endl;
    }
    else
    {
        check = 1;
    }
}
}


int main()
{
files();
}

我试图让它列出所有文件而没有异常,但它工作正常但是当我添加第二个for循环而第二个directory_iterator出错时。

2 个答案:

答案 0 :(得分:0)

潜在的问题是boost::filesystem::directory_iterator是一个输入迭代器,不能保证保持相等性:请参阅directory_iterator documentation处的注释。

在实现中,它可能正在使用类似POSIX opendirreaddir接口的东西,其中有一个基础打开文件描述符,从中连续读取目录条目。

因此,在分配后推进可能与iterator2共享相同基础状态的iterator1可能正在改变iterator1将返回的内容。

实际上,在我的测试平台(Linux,g ++)上,iterator2循环完成后,iterator2等于结束迭代器,iterator1也等于结束迭代器和程序尝试访问文件名时出现段错误。

简而言之,iterator2和iterator1没有独立的状态,即使应该是这种情况并不明显。要解决此问题,最简单的方法是记录您在std::set(或C ++ 11中的std::unordered_set)中看到的文件大小,并且只打印路径该集合尚未包含该文件大小。

我在这里添加了一个使用std::set来执行此操作的版本。为了简单起见,我忽略了递归下降到子目录中。您需要确定是否要省略与同一子目录中的文件大小相同的文件,或者省略任何子目录中的文件。

#include <boost/filesystem.hpp>      
#include <iostream>
#include <string>
#include <set>

using namespace std;
void files(string a = ".")
{
    boost::filesystem::directory_iterator iterator(a),dir_end;
    std::set<uintmax_t> file_sizes;

    for (; iterator != dir_end; ++iterator) {
        bool emit = true;

        if (!is_directory(iterator->path())) {
            uintmax_t size = file_size(iterator->path());
            if (file_sizes.find(size) == file_sizes.end()) {
                // set does not contain this file size yet.
                file_sizes.insert(size);
            }
            else {
                // set already contains this file size, so don't print path
                emit = false;
            }
        }

        if (emit) {
            cout << (iterator->path().filename()) << endl;
        }
    }
}

int main() {
    files();
}

答案 1 :(得分:0)

我自己做了一个手指练习。

我意识到它可能过于通用/复杂而无法达到您的目的(例如,它可以优雅地处理由于例如权限问题导致文件大小失败的情况),但也许您仍然可以获得一些灵感从它:

<强> Live On Coliru

#include <boost/filesystem.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <map>
#include <iostream>
#include <string>
#include <cstdio>

namespace fs = boost::filesystem;

template <
    typename KeyFunc,
    typename OutputUnique,
    typename HandleDupe,
    typename Path = boost::filesystem::path,
    typename KeyType = decltype(std::declval<KeyFunc>()(Path{})),
    typename Record = std::pair<boost::optional<KeyType> const, Path>
>
void files(std::string const& curdir, OutputUnique output, KeyFunc const& key, HandleDupe const& handler)
{
    using namespace boost::adaptors;
    using namespace boost;

    using path  = fs::path;
    using paths = std::vector<path>;

    auto safe_key = [&key](path const& p) { 
        optional<KeyType> sz;
        try { sz = key(p); } catch(...) { }
        return std::make_pair(sz, p); 
    };

    std::function<void(path const&)> recurse = [&](path const& curdir) {
        paths files;
        paths dirs;

        std::map<optional<KeyType>, path> seen;

        try {
            auto entries 
                = make_iterator_range(fs::directory_iterator(curdir), {})
                | transformed(std::mem_fn(&fs::directory_entry::path))
                ;

            std::partition_copy(
                    entries.begin(), entries.end(),
                    back_inserter(dirs),
                    back_inserter(files),
                    [](path const& p) { return is_directory(p); }
                );

            for(auto& f: files) {
                auto insertion = seen.insert(safe_key(f));

                if (!insertion.second && insertion.first->first)
                    handler(*insertion.first, safe_key(f));
                else
                    *output++ = f;
            }

            boost::for_each(dirs, recurse);
        } catch(std::exception const& e) {
            std::cerr << "Skipping " << curdir << ": " << e.what() << "\n";
        }
    };

    recurse(curdir);
}

template <typename OutputUnique = std::ostream_iterator<fs::path> >
void files(std::string const& curdir = ".", OutputUnique output = std::ostream_iterator<fs::path>(std::cout, "\n"))
{
    using fs::path;
    using Record = std::pair<boost::optional<size_t> const, path>;
    files(
            curdir,
            output, 
            [](path const&p) { return file_size(p); },
            [](Record const&, Record const&) { }
         );
}

#include <boost/function_output_iterator.hpp>

int main() { 
    files("."); // prints non-dupes recursively

    // advanced use: print nothing for non-dupes, but print the duplicate pairs
    auto devnull = boost::make_function_output_iterator([](fs::path){});
    files(".", 
            devnull,                                     // back_inserter(some_vector), etc.
            [](fs::path const& p){return file_size(p);}, // some other key? 
            [](auto const& dupe, auto const& orig) {
                std::cout << "Duplicate size (" << *dupe.first << ") in " << dupe.second << "\n"
                          << "\tOriginal: " << orig.second << "\n";
            }); 
}

打印

"./main.cpp"
"./a.out"
Duplicate size (3208) in "./main.cpp"
    Original: "./dupe.cpp"