问题标签 [rvo]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - 我正在从函数返回未命名的对象。为什么 RVO 仍然起作用?
关于这一点:为什么 std::move 会阻止 RVO?有人写道:“因此,如果表达式是局部变量的名称,则只有在返回语句中才会出现复制省略”
但是我用 GCC 做了一个小测试:
producerX 函数不返回命名值。它返回一个未命名的临时对象。然而,RVO 仍然启动,并且没有复制或移动构造。main 中的 x 对象是就地构造的。如果我这样写produceX:
它的行为方式相同(这是预期的)。但是为什么在前一种情况下允许 RVO 呢?
c++ - 为什么将临时返回对象分配给引用时需要公共复制构造函数?
考虑以下代码:
此代码无法在 VC++ 2010 上编译。
我相信它与 RVO 有关,但我想更好地了解它在做什么。我认为没有理由必须调用复制构造函数。
这是我所期望的:
- 输入 f()
- 调用默认构造函数
- 调用移动构造函数以返回对象(可能由 RVO 优化)
- 将临时返回对象分配给引用 p
事实上,如果我将复制构造函数公开,它就会完全按照这种方式编译和工作。永远不会调用复制构造函数。x 的最终值为 0。
c++ - C++:RVO、NRVO 和返回本地对象
我刚刚阅读了 RVO(返回值优化)和 NRVO(命名返回值优化)。下面是两个例子
这是有道理的,一个不错的编译器优化。但是,我从 Stanley Lippman 的“C++ 入门”中读到“从不返回指向本地对象的引用或指针”(第 6.3.2 章),示例代码是
我不明白,这个示例与 RVO 示例有什么不同吗?如果它们相同,我如何确保编译器会进行 RVO 优化,而不是由于调用堆栈展开而导致未定义的行为?
c++ - 在调用函数的范围内构造返回的对象
是否可以强制 C++ 在调用函数的范围内构造对象?我的意思是明确地做返回值优化(RVO)所做的事情。
我有一些容器类在派生链中。由于类是用堆栈数据构造的,因此无法返回,所以我禁用了复制构造函数和赋值运算符。对于每个类,我都提供了一个迭代器。每个迭代器的构造函数只有一个参数:指向容器类的指针。要获取迭代器,我想使用这个函数:
在这种情况下:
编译器发出错误,抱怨无法复制 BindPackIterator 对象。请记住,我禁用了它们。
我想要发生的是在调用函数的范围内实例化 BindPackIterator 以避免复制或移动操作。
在这种特殊情况下,我知道我可以做一个解决方法,将 begin 函数更改为返回一个 BindPack 指针,
我用 decltype 和这个结构做了一些实验,但没有成功:
这只是我目前感到沮丧的一个例子。在其他项目中,明显的解决方案是让函数在调用函数的范围内实例化一个对象。在某些情况下,移动构造函数 (foo&&) 会有所帮助,但对于具有许多数据成员的对象,即使这样也可能效率低下。是否有允许在调用者范围内构造/实例化对象的设计模式?
c++ - 返回值优化是否需要声明一个拷贝构造函数
我发现英特尔编译器不会为 std::array 对象生成返回值优化。以下代码恰好位于我的程序的内部循环中,并没有尽其所能进行优化。
我发现这种行为来自于我的标准库实现没有为 std::array 显式定义复制构造函数这一事实。以下代码演示了这一点:
当你编译它时
报告文件显示
这证明编译器生成了 RVO(更改了 f 的签名,以便可以将新创建的对象放入调用站点的堆栈中)。但是如果你注释掉声明的那行,Test(const Test& x);
报告文件会显示
这证明没有生成RVO。
在定义 RVO 的 C++11 标准的 12.8.31 中,他们给出的示例有一个复制构造函数。那么,这是英特尔编译器的“错误”还是符合标准的实现?
c++ - 返回值优化和构建结构的函数
我有一个“构建”要返回的结构的函数:
我应该c
离开这个功能吗?我意识到,(N)RVO 经常可以就地构建对象,但有时可能并非如此。什么时候不能完成 (N)RVO,因此,我应该什么时候移动函数的对象?
换句话说,这显然是返回的临时的 RVO。问题变成了,NRVO(命名返回值优化)会发生c
吗?将c
在原地构造(在函数的调用点,在临时stuff
结构内部),或者将c
在函数中构造,然后复制到调用点的结构中。
c++ - 哪些因素决定是否使用 (N)VRO?
(受这个问题的启发,不幸的是这是主观的)。
哪些因素会影响编译器是否选择应用 (N)VRO?
我知道有两大类因素,因为优化器需要回答关于 (N)VRO 决策的两个问题:(1)它甚至可能吗?(2)它是一种优化吗?我希望每个因素都只适用于这两个问题中的一个。
请不要对优化部分进行毫无根据的猜测。当您可以准确解释它如何影响优化时,可以列出一个因素,或者一个现有编译器使用的因素。但不要在sizeof(T)
不解释这如何影响申请 (N)VRO 的决定的情况下说。
c++ - 为什么移动语义和 RVO 都不能按预期工作?
我最近在我的方程求解器中偶然发现了一些奇怪的行为,这让我问自己是否真的理解移动语义和 RVO 是如何协同工作的。
这个论坛上有很多相关的问题,我也阅读了很多关于这个的一般解释。但我的问题似乎很具体,所以我希望有人能帮助我。
涉及的结构有点复杂,但至少可以分解为:
现在让我们考虑以下短程序:
这些是我在运行此代码之前的期望:
- 该
Example
方法实例化一个本地Foo
对象,从而调用默认的ctor。 Example
按值返回本地Foo
对象。但是,由于RVO,我希望此副本会被省略。- 随后对复制 ctor的调用也可能会得到优化。相反
a
,可能会给出内部临时对象的地址Example
。 - 为了计算表达式
a + a
,operator+
在左侧操作数上调用该方法。 - 右侧操作数按值传递,因此可能必须制作本地副本。
- 在方法内部,
operator+=
在该副本上调用并*this
通过引用传递。 - 现在
operator+=
再次返回对同一个本地副本的引用,跳回到调用operator+
方法的返回语句。 - 被引用的对象最终是按值返回的。在这里,我预计另一个副本省略,因为本地副本的值
b
现在只需要保留(就像之前在步骤 2 和 3 中发生的那样)。 - 两个对象
a
最终b
都将超出范围,因此调用它们的析构函数。
令人惊讶的观察结果(至少对我而言)是,在第 8 步中,深层副本没有被优化(无论使用什么编译器选项)。相反,输出如下所示:
在我看来,以下小的变化operator+
根本没有任何区别:
然而,这一次的结果完全不同:
显然,编译器现在将其识别rhs
为xvalue(如果我明确地编写它也会这样做)并改为return move(rhs += *this);
调用move ctor 。
此外,使用该-fno-elide-constructors
选项,您将始终获得以下信息:
据我所知,编译器必须去
- RVO(如果可能),或
- 移动建筑(如果可能),或
- 复制构造(否则),
以该顺序。所以我的问题是:有人可以向我解释一下,步骤 8 中到底发生了什么以及为什么上述优先规则不适用(或者如果是,我在这里看不到的是什么)?很抱歉这个冗长的例子,并在此先感谢。
我目前正在使用 gcc mingw-w64 x86-64 v.4.9.2-std=c++11
并关闭优化。
ps - 请抵制就如何编写正确的 OO 代码并确保封装提供建议的冲动;-)
c++ - 指向堆栈分配对象和移动构造的指针
注意:这是对我不久前发布的问题的完整重新措辞。如果您发现它们重复,请关闭另一个。
我的问题很笼统,但似乎可以根据一个具体的简单示例更容易地解释它。所以想象一下我想模拟办公室的用电量。让我们假设只有光和加热。
重点是:
1.Time
不能移动为数据成员Light
,或者Heating
因为它的更改不是来自这些类中的任何一个。
2.Time
不必作为参数显式传递给Light
. 实际上,Light
在程序的任何部分都可能存在不希望Time
作为参数提供的引用。
现在,Simulation
只要不是复制/移动构造,就可以完美找到。因为如果是,Light
也将构造复制/移动,并且默认情况下,指向时间的指针将指向复制/移动Time
的旧Simulation
实例中的。然而,Simulation
实际上是SimulationBuilder::build()
在返回语句和对象创建之间构建的复制/移动main()
现在有很多方法可以解决这个问题:
1:依靠复制省略。在这种情况下(在我的真实代码中),标准似乎允许复制省略。但不是必需的,事实上,它并没有被 clang -O3 忽略。更准确地说,clang 省略Simulation
了复制,但确实将移动 ctor 称为Light
. 另请注意,依赖于实现相关的时间并不可靠。
2:在中定义一个move-ctor Simulation
:
这确实有效,但这里的大问题是它削弱了封装:现在Simulation
必须知道Light
在移动过程中需要更多信息。在这个简化的例子中,这并不算太糟糕,但是想象timePtr
不是直接在Light
而是在它的一个子子子成员中。那我得写
这完全打破了封装和得墨忒耳定律。即使在委派职能时,我也觉得这很可怕。
3:使用某种观察者模式,在复制/移动构造时Time
被观察Light
并发送消息,以便Light
在接收消息时更改其指针。我必须承认我懒得写一个完整的例子,但我认为它会很重,我不确定增加的复杂性是否值得。
4:在中使用拥有指针Simulation
:
现在当Simulation
被移动时,Time
内存不是,所以指针 inLight
不会失效。实际上这是几乎所有其他面向对象语言所做的,因为所有对象都是在堆上创建的。目前,我赞成这个解决方案,但仍然认为它并不完美:堆分配可能会很慢,但更重要的是它看起来并不习惯。我听说 B. Stroustrup 说你不应该在不需要时使用指针,而需要意味着或多或少是多态的。
Simulation
5:就地构造,不被返回SimulationBuilder
(然后复制/移动ctor/assignmentSimulation
可以全部删除)。例如
现在我的问题如下:
1:你会使用什么解决方案?你想到另一个吗?
2:你觉得原来的设计有问题吗?你会怎么做才能修复它?
3:你遇到过这种模式吗?我发现它在我的代码中很常见。一般来说,这不是问题,因为Time
它确实是多态的,因此是堆分配的。
4:回到问题的根源,即“不需要移动,我只想在原地创建一个不可移动的对象,但编译器不允许我这样做”为什么没有C++ 中的简单解决方案,是否有另一种语言的解决方案?
c++ - 我如何确定将完成返回值优化
我编写了按值返回巨大对象的函数。我的同事抱怨它会做冗余复制,并建议通过引用返回对象作为函数参数。我知道将完成返回值优化并消除副本,但代码将用于可由不同编译器编译的库中,我无法对所有编译器进行测试。为了让我的同事相信按价值返回对象是保存的,我需要一些说明它的文档。
我查看了 c++03 标准,但找不到任何关于返回值优化的信息。您能否提供一个文档(标准)的链接,其中定义了 RVO 将被执行。或者,如果它不存在,我可以在哪里找到支持 RVO 的编译器列表?