【问题标题】:std::transform and move semanticsstd::transform 和 move 语义
【发布时间】:2011-06-06 03:12:04
【问题描述】:

我正在使用 Boost.Filesystem 在目录中创建文件列表。我使用boost::filesystem::recursive_directory_iteratorstd::copy 将每个路径作为boost::filesystem::directory_entry 对象放入std::vector 中。我希望作为 std::strings 输出到文件,所以我做了以下 (\n 以避免使用

std::vector<boost::filesystem::directory_entry> buffer; //filled with paths
...
std::vector<std::string> buffer_native(buffer.size());
//transform directory_entry into std::string, and add a \n, so output is formatted without use of <<
std::transform(buffer.begin(),buffer.end(),buffer_native.begin(), [](boost::filesystem::directory_entry de)->std::string
    {
        std::string temp=de.path().string();
        temp+="\n";
        return temp;
    }
    buffer.clear();
    std::copy(buffer_native.begin(),buffer_native.end(),std::ostream_iterator<std::string>(out_file));

但是,这样做的问题是它创建了两个向量,其中的原始向量立即被清除,因为它不需要。这听起来像是移动语义的完美场所,但 n3242 仅提供与 C++98 中相同的两个变换重载。是否可以使用std::transform 实现移动语义?如果不是,写一个自定义循环会更好吗?

我在 Windows XP 上使用 GCC 4.5.2 (MinGW)。

【问题讨论】:

    标签: c++ stl c++11


    【解决方案1】:

    这看起来像是make_move_iterator 的工作:

    std::transform(make_move_iterator(buffer.begin()),
                    make_move_iterator(buffer.end()), buffer_native.begin(),
                    [](boost::filesystem::directory_entry&& de) -> std::string
    {
        // still makes copy :/ perhaps native() would work better, I don't know
        std::string temp = de.path().string();
        temp += "\n";
    
        return temp;
    }
    

    移动迭代器只是一个移动其解引用结果的迭代器。请注意,该类需要支持移动语义才能有所作为;不知道Boost FS有没有。


    请注意,如果您的目标是在单独的行上输出它们,那么您做错了。格式化打印不应该要求输入数据采用某种格式,这违背了目的。在数据中添加换行符只是为了将其格式化为具有换行符是令人讨厌的。无论如何,它由ostream_iterator 为您处理:

    std::copy(buffer.begin(), buffer.end(), //               vvvv
                std::ostream_iterator<std::string>(out_file, "\n"));
    

    任何更复杂的,制作一个用于打印的 lambda;不要事先修改您的数据。

    【讨论】:

    • 只是帮助编译器执行 RVO 或通过返回未命名的临时来移动:return de.path().string() + '\n';
    • 谢谢。我不知道像make_move_iterator 这样的东西甚至存在(我还没有完全阅读n3242)。我不认为 Boost.Filesystem 支持移动语义,虽然我认为他们计划在未来。
    • @mmoran:是的。您可以将 lambda 参数作为参考以避免复制。
    • 根据this,“unary_op 和 binary_op 不得......修改所涉及范围的任何元素。”我认为从输入范围移动将被视为修改其中的元素。
    • @mentalmushroom 我链接到的页面上操作先决条件部分的位置令人困惑,看起来它们仅适用于接受执行策略的版本,但查看实际标准的先决条件'不要说只适用于 ExecutionPolicy 重载。我打算在cppreference页面上留个笔记看看是否可以改进。
    猜你喜欢
    • 2011-07-28
    • 2011-07-28
    • 2018-10-18
    • 2018-03-21
    • 2012-01-02
    • 1970-01-01
    • 2016-04-22
    • 2014-02-27
    • 1970-01-01
    相关资源
    最近更新 更多