【发布时间】:2018-03-09 17:58:25
【问题描述】:
并不是我不信任我的编译器,而是我想知道发生了什么。假设我有
struct Foo {
std::string s;
};
我想创建一个(在堆栈上),填写很长的字符串,然后从我的函数中返回它。
Foo f() {
Foo foo {my_very_long_string};
return foo;
// OR: return Foo {my_very_long_string};
}
我知道有诸如 RVO 和移动语义之类的东西;我怎么知道它们正在被使用,并且在运行时它没有在堆上分配带有数据的新字符串,复制它并释放旧字符串? (除了我的程序会变慢。)
是否使用移动构造函数来重用字符串数据?还是使用 RVO 来实际返回相同的字符串?
【问题讨论】:
-
如果您不信任该程序集,请编译并检查它。在你做类似的事情之前,尽管对代码进行基准测试。如果代码运行良好,就没有理由这样做。
-
“我怎么知道......在运行时它没有分配一个新的字符串......,复制它,然后释放旧的?”你可以保证这不会发生。如果没有 RVO,字符串将被移动而不是复制,因此不会有额外的分配
-
这是一个相当哲学的问题。您如何确定其他人(在这种情况下是标准开发人员)告诉您的任何事情?我想你必须在某个时候相信他们。或者自己挖掘一切,但你知道,生命是短暂的。 :)
-
在一种情况下你必须小心——如果你定义了一个析构函数(或复制 ctor 或复制分配),你不会得到一个为你定义的隐式移动 ctor。因此您的对象变得不可移动,因此会出现副本(包括原本可以移动的字段)
-
“我知道有诸如 RVO 和 move 语义之类的东西;我怎么知道它们正在被使用” (A) 阅读标准或它的适当摘要,了解这些优化可以发生的时间。 (B) 阅读您(完全未知的)编译器生成的程序集,看看是否发生了此类优化确实。