gpt4 book ai didi

c++ - 对于按值传递的重成员,构造函数的初始化列表中真的需要 std::move 吗?

转载 作者:IT老高 更新时间:2023-10-28 12:39:20 28 4
gpt4 key购买 nike

最近我从 cppreference.../vector/emplace_back 中阅读了一个示例:

struct President
{
std::string name;
std::string country;
int year;

President(std::string p_name, std::string p_country, int p_year)
: name(std::move(p_name)), country(std::move(p_country)), year(p_year)
{
std::cout << "I am being constructed.\n";
}

我的问题:这 std::move 真的需要吗?我的观点是这个 p_name 没有用在构造函数的主体中,所以,也许语言中有一些规则默认使用 move 语义?

将初始化列表中的 std::move 添加到每个重成员(如 std::stringstd::vector)会非常烦人。想象一下数百个用 C++03 编写的 KLOC 项目——我们是否应该在任何地方添加这个 std::move

这个问题:move-constructor-and-initialization-list答案是:

As a golden rule, whenever you take something by rvalue reference, you need to use it inside std::move, and whenever you take something by universal reference (i.e. deduced templated type with &&), you need to use it inside std::forward

但我不确定:按值传递而不是通用引用?

[更新]

为了让我的问题更清楚。可以将构造函数参数视为 XValue - 我的意思是过期值吗?

在这个例子中我们不使用 std::move:

std::string getName()
{
std::string local = "Hello SO!";
return local; // std::move(local) is not needed nor probably correct
}

那么,这里是否需要:

void President::setDefaultName()
{
std::string local = "SO";
name = local; // std::move OR not std::move?
}

对我来说,这个局部变量是过期变量 - 所以可以应用 move 语义......这类似于按值传递的参数......

最佳答案

My question: is this std::move really needed? My point is that compiler sees that this p_name is not used in the body of constructor, so, maybe, there is some rule to use move semantics for it by default?

一般来说,当你想把一个左值变成一个右值,那么是的,你需要一个std::move()。另见 Do C++11 compilers turn local variables into rvalues when they can during code optimization?

void President::setDefaultName()
{
std::string local = "SO";
name = local; // std::move OR not std::move?
}

For me this local variable is expiring variable - so move semantics could be applied... And this similar to arguments passed by value....

在这里,我希望优化器消除多余的 local ALTOGETHER;不幸的是,实际情况并非如此。当内存开始发挥作用时,编译器优化会变得很棘手,请参阅 BoostCon 2013 Keynote: Chandler Carruth: Optimizing the Emergent Structures of C++ .我从 Chandler 的演讲中得出的一个结论是,当涉及到堆分配的内存时,优化器往往会放弃。

请参阅下面的代码,了解一个令人失望的示例。在这个例子中我没有使用 std::string 因为这是一个高度优化的类,带有内联汇编代码,通常会产生违反直觉的生成代码。为了增加侮辱, std::string 粗略地说至少是 gcc 4.7.2 中的引用计数共享指针( copy-on-write optimization ,现在被 std::的 2011 标准禁止字符串)。所以没有std::string的示例代码:

#include <algorithm>
#include <cstdio>

int main() {
char literal[] = { "string literal" };
int len = sizeof literal;
char* buffer = new char[len];
std::copy(literal, literal+len, buffer);
std::printf("%s\n", buffer);
delete[] buffer;
}

显然,根据“as-if”规则,生成的代码可以优化为:

int main() {
std::printf("string literal\n");
}

我已经在启用链接时间优化 (LTO) 的 GCC 4.9.0 和 Clang 3.5 上进行了尝试,但没有一个可以将代码优化到这个级别。我查看了生成的汇编代码:它们都在堆上分配了内存并进行了复制。嗯,是的,这令人失望。

堆栈分配的内存不同:

#include <algorithm>
#include <cstdio>

int main() {
char literal[] = { "string literal" };
const int len = sizeof literal;
char buffer[len];
std::copy(literal, literal+len, buffer);
std::printf("%s\n", buffer);
}

我已经检查了汇编代码:在这里,编译器能够将代码基本上简化为 std::printf("string literal\n"); .

因此,我对示例代码中多余的 local 可以被消除的期望并非完全不受支持:正如我后面的堆栈分配数组示例所示,可以做到。

Imagine hundreds of KLOC project written in C++03 - shall we add everywhere this std::move?
[...]
But I am not sure: passing by value is rather not universal reference?

"Want speed? Measure." (作者 Howard Hinnant)

您很容易发现自己进行优化只是为了发现您的优化使代码变慢。 :( 我的建议与 Howard Hinnant 的建议相同:衡量。

std::string getName()
{
std::string local = "Hello SO!";
return local; // std::move(local) is not needed nor probably correct
}

是的,但是我们有针对这种特殊情况的规则:它被称为命名返回值优化 (NRVO)。

关于c++ - 对于按值传递的重成员,构造函数的初始化列表中真的需要 std::move 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23929800/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com