编辑:考虑以下 2 个示例:
std::string x;
{
std::string y = "extremely long text ...";
...
x = y; // *** (1)
}
do_something_with(x);
struct Y
{
Y();
Y(const Y&);
Y(Y&&);
... // many "heavy" members
};
struct X
{
X(Y y) : y_(std::move(y)) { }
Y y_;
}
X foo()
{
Y y;
...
return y; // *** (2)
}
在这两个示例中,第 (1) 和 (2) 行的 y 都接近其生命周期的尽头,即将被销毁。很明显,它可以被视为右值并在两种情况下都可以移动。在 (1) 中,它的内容可以移动到 x 中,在 (2) 中移动到 X().y_ 的临时实例中。
我的问题是:
1) 是否会在上述任一示例中移动? (a) 如果是,根据什么标准条款。 (b) 如果不是,为什么不呢?这是标准中的遗漏还是有其他我没有想到的原因?
2) 如果以上答案是否定的。在第一个示例中,我可以将 (1) 更改为 x = std::move(y) 以强制编译器执行移动。在第二个示例中,我可以做什么来向编译器指示 y 可以移动? 返回 std::move(y)?
注意:我故意在 (2) 中返回 Y 的实例而不是 X 以避免 (N)RVO。
最佳答案
对于您的第一个示例,答案显然是“否”。该标准允许编译器在处理函数的返回值时对拷贝采取各种自由(即使有副作用)。我想,在 std::string 的特定情况下,编译器可以“知道”复制和移动都没有任何副作用,因此它可以在 as-if 规则下用一个代替另一个.但是,如果我们有类似的东西:
struct foo {
foo(foo const &f) { std::cout << "copy ctor\n"; }
foo(foo &&f) { std::cout << "move ctor\n"; }
};
foo outer;
{
foo inner;
// ...
outer = inner;
}
...一个正常运行的编译器必须生成打印出“copy ctor”而不是“move ctor”的代码。确实没有具体的引文——相反,有一些引文在谈论函数返回值的异常,这在此处不适用,因为我们不处理函数的返回值。
至于为什么没有人处理这个:我猜这只是因为没有人打扰。函数的返回值经常发生,因此值得花大量精力对其进行优化。创建一个非功能 block ,并在 block 中创建一个值,您继续将其复制到 block 外的值以保持其可见性,这种情况很少发生,以至于似乎不太可能有人写出提案。
这个例子是至少从一个函数返回一个值——所以我们必须看看允许移动而不是复制的异常的细节。
这里,规则是(N4659,§[class.copy.elision]/3):
In the following copy-initialization contexts, a move operation might be used instead of a copy operation:
- If the expression in a return statement (9.6.3) is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression,
[...]
overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If the first overload resolution fails or was not performed, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.
return 语句中的表达式 (y) 是一个 id 表达式,它命名一个对象,该对象具有在最内层封闭函数的主体中声明的自动存储持续时间,因此编译器必须执行两个 -阶段过载解决方案。
但是,此时它正在寻找的是一个构造函数,用于从 Y 创建 X。 X 定义了一个(并且只有一个)这样的构造函数——但是该构造函数接收它的 Y 按值。因为这是唯一可用的构造函数,所以它是在重载决策中“获胜”的构造函数。由于它按值获取参数,因此我们首先尝试将 y 视为右值的重载决策实际上没有任何区别,因为 X 没有接收它的正确类型的构造函数。
现在,如果我们将 X 定义成这样:
struct X
{
X(Y &&y);
X(Y const &y);
Y y_;
}
...then 两阶段重载决议将产生真正的效果——即使 y 指定了一个左值,第一轮重载决议将其视为一个右值,因此将选择 X(Y &&y) 并用于创建返回的临时 X——也就是说,我们将得到一个移动而不是一个复制(即使 y 是左值,我们有一个采用左值引用的复制构造函数)。
关于c++ - 范围末尾的左值可以被视为右值吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45179514/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是
我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法