当隐式调用构造函数时,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::copy
和 std::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)));
我今天遇到了以下行为,对其内部工作原理有疑问。
我有一个字符串向量,我需要将其转换为文件系统路径,我使用复制方法这样做,因为我知道它会调用适当的字符串构造函数。
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::copy
和 std::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)));