问题标签 [copy-elision]

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.

0 投票
1 回答
569 浏览

c++ - 复制省略可见副作用

考虑这段代码:

当我编译时

g++ -std=c++11 -fno-elide-constructors test.cpp

输出是

ctor ctor 副本 0

这是我所期望的,因为 in Foo b = 10,10是从 隐式构造的int,然后b是从 构造的副本Foo。此外,我的复制构造函数不做任何事情,所以成员_a仍然存在0(因为它是类内初始化的)。

但是,当我使用复制省略时

g++ -std=c++11 test.cpp

输出是

演员 演员 10

至少可以说这是令人惊讶的。我知道这里省略了复制构造函数,但这是一个严重的副作用(成员一次初始化为 0 和一次初始化为 10 的事实),因为它会影响代码路径的其余部分。

这种行为正常吗?

0 投票
2 回答
289 浏览

c++ - 自动和复制省略

当使用 auto 并提交到特定类型时,复制省略的确切规则是什么?(请参阅:GotW - 几乎总是自动)。

据我了解,移动/复制构造函数必须是可访问的,即使它不常用。但是,在下面的示例中, unique_ptrfstream之间有什么区别?(与noexcept 有关?)

0 投票
3 回答
202 浏览

c++ - 返回不能按值复制的对象

我有一个对象,它的复制操作太慢了,所以我决定这样delete做并强制用户只移动。无论如何,这个对象伤口的副本没有多大意义。但后来我有这个功能:

即使这里发生了复制省略并且没有调用复制构造函数,这也无法编译,因为需要复制构造函数存在并且可以访问。这是我的第二次尝试:

这编译。耶!

但是在尝试使用它时又出现了一个新问题:

这又需要一个复制构造函数。即使明确使用move,我也无法让它工作:

我来的唯一解决方案是:

x必须是非常量的,因为它稍后会被改变。

如何处理?

0 投票
2 回答
207 浏览

c++ - 复制省略误区

编译后

g++ Copy.cpp -std=c++11 -fno-elide-constructors

输出是:

定义常数

复制构造

复制构造

我的问题是:为什么 2 Copy Consr ?我认为只需要 1 份副本。

我可能猜测 func1() 抛出了一个临时对象,并且这个临时对象需要被复制到另一个内存区域,并且必须再次从该区域复制 func2() 参数,但它对我来说是模糊的。

你能详细解释一下吗?

0 投票
2 回答
94 浏览

c++ - 为什么复制省略如此有限?

我关心的两种复制省略形式非常有限。它只允许在 return 语句中和使用临时变量初始化变量时。所以这些不涉及复制省略:

这是什么原因?这是技术限制..还是..?

0 投票
2 回答
247 浏览

c++ - 模板类调用过多的析构函数 (N)RVO 优化

我正在尝试编写自己的智能指针 (C++11) 和堆栈有一个问题,可以通过下一个示例来解释:

输出:

如您所见,这里有很多析构函数。在我看来,复制省略和模板构造函数之间的交互存在一些问题,但我不知道这种错误可能是什么原因。我试图通过添加explicit复制构造函数和强制编译器使用我的模板构造函数来解决问题:

得到下一个输出:

这里一切看起来都不错,但它看起来不像一个干净的解决方案。有更好的选择吗?

0 投票
4 回答
1034 浏览

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 说你不应该在不需要时使用指针,而需要意味着或多或少是多态的。

Simulation5:就地构造,不被返回SimulationBuilder(然后复制/移动ctor/assignmentSimulation可以全部删除)。例如

现在我的问题如下:

1:你会使用什么解决方案?你想到另一个吗?

2:你觉得原来的设计有问题吗?你会怎么做才能修复它?

3:你遇到过这种模式吗?我发现它在我的代码中很常见。一般来说,这不是问题,因为Time它确实是多态的,因此是堆分配的。

4:回到问题的根源,即“不需要移动,我只想在原地创建一个不可移动的对象,但编译器不允许我这样做”为什么没有C++ 中的简单解决方案,是否有另一种语言的解决方案?

0 投票
2 回答
444 浏览

c++ - 按值传递临时值时如何避免移动省略?

在以下代码中:

Widget 对象将始终就地构造(在 foo 函数内部),因此不会发生移动构造(至少对于我尝试过的所有编译器)。以实际发生移动构造的方式(没有显式移动,即使用std :: move)将临时值传递给函数的简单示例是什么?

0 投票
1 回答
1359 浏览

c++ - 如何使用 C++11 移动语义从函数返回 std::vector?

我知道 C++11 有来自这个链接的移动语义: 现代 C++ 风格的元素

但它没有介绍如何使用移动语义返回向量。这该怎么做?

0 投票
2 回答
6438 浏览

c++ - C中的返回值优化和复制省略

有些人不知道在 C 中可以按值传递和返回结构。我的问题是编译器在返回 C 中的结构时会制作不必要的副本。C 编译器(如 GCC)是否使用返回值优化(RVO)优化,或者这只是 C++ 的概念?我所读到的关于 RVO 和复制省略的所有内容都是关于 C++ 的。

让我们考虑一个例子。我目前正在 C 中实现双双数据类型(或者更确切地说是 float-float,因为我发现它很容易进行单元测试)。考虑以下代码。

编译器会制作doublefloat我返回的值的临时副本还是可以省略临时副本?

C 中的命名返回值优化 (NRVO) 怎么样?我有另一个功能

在这种情况下,我将返回一个命名结构。这种情况下的临时副本可以省略吗?

应该说这是 C 的一个普遍问题,我在这里使用的代码示例只是示例(当我优化它时,无论如何我都会使用带有内在函数的 SIMD)。我知道我可以查看程序集输出以了解编译器的作用,但我认为这是一个有趣的问题。