Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在实践中何时调用移动构造函数?_C++_Move Semantics_Move Constructor_Copy Elision - Fatal编程技术网

C++ 在实践中何时调用移动构造函数?

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

我最近学习了移动构造函数,但很多在线资源并没有提到复制省略。复制省略对我来说也很有意义,但它让我想知道,如果没有一个超级精心设计的示例,何时才能调用move构造函数

来自一篇向我解释移动语义的流行SO帖子

这篇文章说,这两个函数都应该调用move构造函数,因为它们接受临时变量。但是,这些函数实际上都没有调用move构造函数(我已经调用过),它们都只是执行复制省略,除非您通过显式编写
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补充道。从技术上讲,第一次调整大小可以为(至少)分配足够的空间12
foo
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