当隐式调用构造函数时,std::move 的行为是什么?

What is the behavior of std::move when a constructor is being implicitly called?

我今天遇到了以下行为,对其内部工作原理有疑问。

我有一个字符串向量,我需要将其转换为文件系统路径,我使用复制方法这样做,因为我知道它会调用适当的字符串构造函数。

std::vector<std::string> strings;
std::vector<boost::filesystem::path> paths;
std::copy(strings.begin(), strings.end(), std::back_inserter(paths));

通常,如果我不进行转换并且不再需要旧的 collection,我会使用 std::move() 来节省资源。但我认为 std::copy() 在这里调用会更好,因为我会隐式创建新的 object。但出于病态的好奇心,我还是尝试调用 std::move(),没想到它会起作用。它确实奏效了!

std::vector<std::string> strings;
std::vector<boost::filesystem::path> paths;
std::move(strings.begin(), strings.end(), std::back_inserter(paths));

有人知道这里发生了什么吗?在此之后输入数组的状态是什么?不安全吗?字符串是否被复制,或者它们实际上被移动到构造的 object?

这两种变体都是安全的并且应该有效。现在(提升 1.66)使用 move 没有任何好处,因为没有 boost::filesystem::path 构造函数通过右值引用获取源字符串(并移动它)。如果将来要添加,则可能首选第二个变体。

然而,如果 boost 开发人员决定最终声明将源字符串作为 explicit 的构造函数,那么这两种变体都将停止编译。所以更好的方法是手动移动。无论相应的路径构造函数是否为 explicit,此代码都将起作用,并且在实现时可以利用采用右值引用的构造函数:

paths.reserve(strings.size());
for(auto & source_path: strings)
{
    paths.emplace_back(::std::move(source_path));
}

目前在您的示例中使用 std::copystd::move 之间没有区别,因为没有 boost::filesystem::path(string&&) 构造函数。

但它可能会在未来的版本中添加。

一般来说,您应该假设对象在使用 std::move 后处于 moved-from 状态。

因此,如果您之后从未使用过 strings(除非重置),请使用 std::move。 否则使用 std::copy。现在性能上不会有任何差异。

正如其他人所提到的,它没有影响,因为当前目的地 boost::filesystem::path 没有在其构造函数中使用 r-value 引用。

但也如前所述,move 将来可能会更有效,因为任何更改都将使代码变得更有效,而无需对您的源代码进行任何更改。

BUT 而不是复制到结构中为什么不使用移动构造。

std::vector<boost::filesystem::path> paths;
std::copy(strings.begin(), strings.end(), std::back_inserter(paths));

可以写成:

std::vector<boost::filesystem::path> paths(
                                      std::make_move_iterator(std::begin(paths)),
                                      std::make_move_iterator(std::end(paths)));