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

时间:2018-03-11 18:25:51

标签: c++ stl copy move

我今天遇到了以下行为,并对其内部运作提出了疑问。

我有一个字符串向量,我需要转换为文件系统路径,我使用copy方法,知道它会调用相应的字符串构造函数。

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

通常如果我没有转换并且不再需要旧的集合,我会使用std::move()来节省资源。但我认为std::copy()会更好地调用,因为我会隐式创建新对象。但出于病态的好奇心,我试着打电话给std::move(),而不是期待它发挥作用。它确实有效!

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

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

3 个答案:

答案 0 :(得分:1)

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

然而,如果boost devs决定最终声明构造函数将源字符串作为explicit,则两个变体都将停止编译。因此,更好的方法是手动移动。无论相应的路径构造函数是否为explicit,此代码都将起作用,并且可以在构造函数实现时使用构造函数获取右值引用:

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

答案 1 :(得分:1)

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

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

通常,您应该假设对象在使用std::move后处于移动状态。

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

答案 2 :(得分:1)

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

但同样提到move未来可能更有效,因为任何更改都会让代码变得更有效,而不会对您的来源进行任何更改。

但是而不是复制到结构中,为什么不用移动构建。

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)));