返回无用对象的元组

return tuple of uncopyable objects

本文关键字:元组 对象 无用 返回      更新时间:2023-10-16

考虑以下内容:

#include <fstream>
#include <tuple>
#include <utility>
#include <vector>
const auto length_of_file = [](auto & file){
    file.seekg(0, std::ios::end);
    std::streampos length = file.tellg();
    file.seekg(0, std::ios::beg);
    return length;
};
int main(int, char * []) {
    const auto check_and_read = [](const auto & filename){
        std::ifstream file(filename, std::ios::binary);
        file.exceptions(std::ios::failbit | std::ios::badbit);
        std::vector<std::byte> data(length_of_file(file));
        file.read(reinterpret_cast<char*>(data.data()), data.size());
        return std::make_tuple(file, data);
    };
    auto [file, data] = check_and_read("foo.txt");
}

这不会编译,因为它想要复制file,这是不可能的。

return std::make_tuple(std::move(file), data);有效,但是我问自己»这是否意味着它正在复制而不是现在移动data

却都不

const auto check_and_read = [](const auto & filename)
-> std::tuple<std::ifstream, std::vector<std::byte>> {
…
return {file, data}

也不(不应该从RVALUE参考的元组中进行此移动构造吗?(

const auto check_and_read = [](const auto & filename)
-> std::tuple<std::ifstream, std::vector<std::byte>> {
…
return std::forward_as_tuple(file, data);

似乎有效。

是否有一些标准方法可以确保在返回多个参数的返回而无需单独std::move的情况下移动施工?

考虑以下内容:

std::tuple<std::string, std::string> foo() {
  std::string a = "hello";
  return {a, a};
}

您在特定表达式中使用filedata的用法隐含地安全可移动并不意味着即使对于非常相似的表达方式也是如此。

编译器必须确定命名的标识符注定要将其视为R值,并且这种分析将很快变得不合理地复杂。

没有标准功能,但这应该起作用(C 17(:

template <class... Types>
auto move_to_tuple(Types&&... args) {
    return std::make_tuple(std::move(args)...);
}

移动永远不会被隐式执行,除非在通常考虑省略但碰巧是不可能的情况下作为后备。目前(嗯,至少据我所知(,这意味着隐式移动只能作为RVO和NRVO的后备。

filedata永远不会考虑省略。RVO和NRVO都不适用于他们。仅考虑返回的元组,因为在这种情况下是RVO。因此:

return std::make_tuple(std::move(file), data);

将通过RVO填充元组,移动文件并复制数据。所以你应该这样做:

return std::make_tuple(std::move(file), std::move(data));