C++ 在实践中何时调用移动构造函数?
我最近学习了移动构造函数,但很多在线资源并没有提到复制省略。复制省略对我来说也很有意义,但它让我想知道,如果没有一个超级精心设计的示例,何时才能调用move构造函数 来自一篇向我解释移动语义的流行SO帖子 这篇文章说,这两个函数都应该调用move构造函数,因为它们接受临时变量。但是,这些函数实际上都没有调用move构造函数(我已经调用过),它们都只是执行复制省略,除非您通过显式编写C++ 在实践中何时调用移动构造函数?,c++,move-semantics,move-constructor,copy-elision,C++,Move Semantics,Move Constructor,Copy Elision,我最近学习了移动构造函数,但很多在线资源并没有提到复制省略。复制省略对我来说也很有意义,但它让我想知道,如果没有一个超级精心设计的示例,何时才能调用move构造函数 来自一篇向我解释移动语义的流行SO帖子 这篇文章说,这两个函数都应该调用move构造函数,因为它们接受临时变量。但是,这些函数实际上都没有调用move构造函数(我已经调用过),它们都只是执行复制省略,除非您通过显式编写std::move来强制它 string b(std::move(x + y)); string c(std::m
std::move
来强制它
string b(std::move(x + y));
string c(std::move(some_function_returning_a_string()));
或者somefunction\u returning\u一个字符串
返回std::move(someString)
。但你为什么要这么做?复制省略甚至比移动语义更有效。那么,调用move构造函数而不是复制省略的自然情况是什么呢
在你们把我指给我看之前,我觉得这个答案要么给出了一些人为的例子,要么其中的一些只是做了复制省略。我对学习在实践中调用移动构造函数很感兴趣
这里有一个测试的链接这是对发布的问题的一个非常技术性的回答。这里将调用Move构造函数,我认为,代码根本不是人为的
struct Foo
{
Foo(std::string str) : str(std::move(str)) { }
std::string str;
}
当使用诸如
std::tuple
、std::pair
或std::variant
之类的包装类型时,Move构造会在临时变量和右值上被隐式调用。添加的间接级别可防止复制省略,最终会调用move构造函数
例如:
#include <tuple>
#include <iostream>
struct SomeType {
SomeType() = default;
SomeType(SomeType&&) {
std::cout << "moved!\n";
}
};
int main() {
std::make_tuple(SomeType{}, 12, SomeType{});
}
#include <iostream>
#include <vector>
int main() {
std::vector<foo> v;
v.resize(5);
v.resize(v.capacity()+1); // force the vector to reallocate
}
在您的示例中,从对象移动的对象是临时对象,但移动时并不总是这样。有时我们知道我们可以移动,因为从对象中移动的对象将不再被使用,即使它不是临时对象。考虑这种类型:
struct foo {
foo() = default;
foo(foo&& f) noexcept {
std::cout << "move\n";
}
};
:
复制或移动不可能被省略,因为元素位于旧位置,必须以某种方式到达内存中的新位置。“(我已测试过)”请详细说明您是如何测试的,好吗?也许问题只是你的方法论。我想大多数时候,你会得到一个移动而不是复制省略。一个例子是不断增长的
std::vector
。如果超出容量,则必须分配新元素对象并将现有对象移动到其中。请注意,C++17更改了有关复制省略的规则,现在在许多情况下强制使用它(以前您可能会通过干预编译器选项来禁用它)。甚至在C++17之前,编译器就经常优化迁移,例如当可以使用RVO(返回值优化)时。“我觉得……答案要么给出了人为的示例,要么其中一些示例只会进行复制省略。”您是对的,现在有些示例保证了复制省略。我怀疑您要求确信其他示例不是人为的。voidfoo(std::string&&s)代码>可能涉及移动构造函数,或者可能使用移动赋值,或者可能根本不移动-取决于Foo的实现<代码>空栏(std::string s)
通过std::string s=“Hello”调用;酒吧(标准:移动);
将使用移动构造函数。我认为OP是专门寻找不需要显式std::move()
的示例。是的,这个示例对我来说似乎很做作。比如为什么要声明一个变量来移动它?@JonReeves OP在问题中从来没有提到过这一点。@JoshuaSegal好的,我想展示一些更容易理解的东西。“我将进行编辑,以包括我多次使用过的实际工作示例。”JoshuaSegal补充道。从技术上讲,第一次调整大小可以为(至少)分配足够的空间12foo
s然后就没有moving@Caleth正确,但这不会改变一个事实,即只要我请求大于初始容量的空间,元素就会被移动。可能v.resize(v.capacity()+1)代码>而不是r.resize(12)代码>将解决这种可能性。我相信在任何情况下都需要重新分配,以保证搬迁的顺利进行。@JoshuaSegal对不起,不,我不是问这个问题的最佳人选。当我仍然专注于C++11时,省略的规则随着时间的推移而改变。不过,你只需要在这里找到一个不允许省略的例子。@JoshuaSegal我的回答正好涵盖了你所问的那种临时例子。
struct foo {
foo() = default;
foo(foo&& f) noexcept {
std::cout << "move\n";
}
};
#include <iostream>
#include <vector>
int main() {
std::vector<foo> v;
v.resize(5);
v.resize(v.capacity()+1); // force the vector to reallocate
}
move
move
move
move
move