问题标签 [move-semantics]

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 投票
2 回答
735 浏览

c++ - 是否有必要从不同的类定义移动构造函数?

考虑以下:

为了充分利用移动语义,是否有必要定义像第二个这样的构造函数?还是会在适当的情况下自动处理?

0 投票
1 回答
127 浏览

c++ - 为 fstream 实现移动的 C++0x 库

在找到如何返回 fstream (C++0x)的答案后,我现在想知道是否有一个当前的 c++0x 库为 fstreams 实现移动(甚至交换)(因为gcc (27.9)没有) . 如果它也是免费的,我会更喜欢。

或者有没有其他方法从函数按值返回 fstreams?

我已经尝试编译libcxx,但它似乎非常特定于 linux/mac,我还需要它在 Solaris 上运行,它不会编译。

我可以解决这个问题(例如通过引用返回),但我想我会问这个,以防万一有一个不涉及修改调用代码的解决方案。

0 投票
5 回答
2456 浏览

c++ - 使交换更快、更容易使用和异常安全

我昨晚睡不着,开始想std::swap。这是熟悉的 C++98 版本:

如果用户定义的类Foo使用外部资源,这是低效的。常见的成语是提供一种方法void Foo::swap(Foo& other)和一种专业化的std::swap<Foo>. 请注意,这不适用于类模板,因为您不能部分特化函数模板,并且在std命名空间中重载名称是非法的。解决方案是在自己的命名空间中编写一个模板函数,并依靠参数依赖查找来找到它。这严重依赖于客户端遵循“using std::swap成语”而不是std::swap直接调用。很脆。

在 C++0x 中,如果Foo具有用户定义的移动构造函数和移动赋值运算符,提供自定义swap方法和std::swap<Foo>专门化几乎没有性能优势,因为 C++0x 版本std::swap使用高效移动而不是副本:

不必再摆弄swap已经为程序员减轻了很多负担。当前的编译器还没有自动生成移动构造函数和移动赋值运算符,但据我所知,这将改变。剩下的唯一问题是异常安全,因为一般来说,移动操作是允许抛出的,这会打开一大堆蠕虫。问题“移出对象的状态究竟是什么?” 使事情进一步复杂化。

std::swap然后我在想,如果一切顺利,C++0x中的语义到底是什么?交换前后对象的状态如何?通常,通过移动操作进行交换不会触及外部资源,只会触及“平面”对象表示本身。

那么,为什么不简单地编写一个swap模板来做到这一点:交换对象表示呢?

这是尽可能高效的:它只是通过原始内存爆炸。它不需要用户的任何干预:不需要定义特殊的交换方法或移动操作。这意味着它甚至可以在 C++98 中工作(请注意,它没有右值引用)。但更重要的是,我们现在可以忘记异常安全问题,因为memcpy从不抛出异常。

我可以看到这种方法的两个潜在问题:

首先,并非所有对象都需要交换。如果类设计器隐藏了复制构造函数或复制赋值运算符,则尝试交换类的对象应该在编译时失败。我们可以简单地引入一些死代码来检查类型上的复制和赋值是否合法:

任何体面的编译器都可以轻松摆脱死代码。(可能有更好的方法来检查“交换一致性”,但这不是重点。重要的是它是可能的)。

其次,某些类型可能会在复制构造函数和复制赋值运算符中执行“不寻常”的操作。例如,他们可能会通知观察者他们的变化。我认为这是一个小问题,因为这类对象可能一开始就不应该提供复制操作。

请让我知道您对这种交换方法的看法。它会在实践中起作用吗?你会用吗?你能确定这会破坏的库类型吗?您是否看到其他问题?讨论!

0 投票
6 回答
126021 浏览

c++ - C++11 右值和移动语义混淆(return 语句)

我试图理解右值引用并移动 C++11 的语义。

这些示例之间有什么区别,其中哪些不进行矢量复制?

第一个例子

第二个例子

第三个例子

0 投票
8 回答
6524 浏览

c++ - 如果我们已经有了 RVO,移动语义会提供什么优化?

据我了解,添加移动语义的目的之一是通过调用特殊构造函数来复制“临时”对象来优化代码。例如,在这个答案中,我们看到它可以用来优化这些string a = x + y东西。因为 x+y 是一个右值表达式,我们可以只复制指向字符串的指针和字符串的大小,而不是深度复制。但正如我们所知,现代编译器支持返回值优化,因此如果不使用移动语义,我们的代码根本不会调用复制构造函数。

为了证明这一点,我编写了以下代码:

在 VC++2010 和 g++ 中以优化模式执行它之后,我得到了空输出。

如果没有它,我的代码仍然运行得更快,它是什么样的优化?你能解释一下我理解错了吗?

0 投票
1 回答
1352 浏览

c++ - 为什么 std::forward 会丢弃 constexpr-ness?

未声明constexprstd::forward将丢弃将参数转发到的任何函数的 constexpr-ness。为什么std::forward不声明constexpr自己,以便它可以保留 constexpr-ness?

示例:(使用 g++ snapshot-2011-02-19 测试)

注意:从技术上讲,制作 constexpr 很容易std::forward,例如,像这样(请注意,在 gstd::forward中已替换为fix::forward):

我的问题是:为什么std::forward不定义 like fix::forward

注意2:这个问题与我关于 constexpr std::tuple的另一个问题有些相关,因为std::forwardnot being是为什么不能通过用右值调用它的 cstr 来创建constexpr的技术原因,但这里的这个问题显然(更)更普遍。std::tuple

0 投票
2 回答
653 浏览

c++11 - 如何在具有右值的算术表达式中实现“最佳”运算符重载分辨率?

首先,我为这个过于冗长的问题道歉。我想不出任何其他方法来准确总结我的问题......现在进入实际问题:

我目前正在尝试使用 C++0x 右值引用...以下代码会产生不需要的行为:

结果输出

构造新的临时对象来存储结果
构造新的临时对象来存储结果
重用临时的第一个操作数来存储结果
重用临时的第一个操作数来存储结果

虽然我曾希望像

构造新的临时
操作数来存储结果 重用临时的第一个操作数来存储结果
重用临时的第二个操作数来存储结果
重用临时的第二个操作数来存储结果

在尝试重新制定编译器正在执行的操作之后(我正在使用带有选项 -std=c++0x 的 MinGW G++ 4.5.2 以防万一),它实际上看起来很合乎逻辑。该标准说,相等优先级的算术运算从左到右进行评估/分组(为什么我假设从右到左我不知道,我想这对我来说更直观)。所以这里发生的事情是编译器首先评估子表达式(v3 + v4)(因为它在括号中?),然后开始从左到右将表达式中的操作与运算符重载进行匹配,导致对子表达式的Vector4 operator + (const Vector4& other)调用表达v1 + v2. 如果我想避免不必要的临时性,我必须确保不超过一个左值操作数出现在任何带括号的子表达式的紧靠左侧,这对于使用这个“库”并且无辜地期待的任何人来说都是违反直觉的最佳性能(如最小化临时创建)。

(我知道我的代码中关于何时添加到 的结果中存在歧义operator + (Vector4&& v1, const Vector4& v2),从而导致警告。但在我的情况下它是无害的,我不想为两个右值引用操作数添加另一个重载- 有人知道是否有办法在 gcc 中禁用此警告?)operator + (Vector4&& other)(v3 + v4)v1 + v2

长话短说,我的问题归结为:是否有任何方式或模式(最好是独立于编译器)这个向量类可以被重写以允许在表达式中任意使用括号,这仍然会导致运算符重载的“最佳”选择(最佳就“性能”而言,即最大化与右值引用的绑定)?也许我要求太多了,这是不可能的……如果是这样,那也没关系。我只是想确保我没有遗漏任何东西。

提前谢谢了

附录

首先感谢我在几分钟内得到的快速回复(!) - 我真的应该早点开始在这里发帖......

在评论中回复变得乏味,所以我认为澄清我对这个类设计的意图是有序的。如果有的话,也许你可以指出我思维过程中的一个基本概念缺陷。

您可能会注意到我在类中没有任何资源,例如堆内存。它的成员甚至只是标量类型。乍一看,这使它成为基于移动语义的优化的可疑候选者(另请参阅这个问题,它实际上帮助我很好地掌握了右值引用背后的概念)。

然而,由于这个类应该是一个原型的类将在性能关键的上下文中使用(准确地说是 3D 引擎),所以我想优化每一个可能的小事情。低复杂度算法和与数学相关的技术(如查找表)当然应该构成大部分优化,因为其他任何东西都只是解决症状而不是消除性能不佳的真正原因。我很清楚这一点。

顺便说一句,我的意图是使用向量和矩阵优化代数表达式,这些向量和矩阵本质上是普通的旧数据结构,其中没有指向数据的指针(主要是由于堆上的数据存在性能缺陷[有取消引用其他指针、缓存注意事项等])。

我不关心移动赋值或构造,我只是不希望在评估复杂代数表达式期间创建比绝对必要的更多临时变量(通常只有一个或两个,例如矩阵和向量)。

这些是我的想法,可能是错误的。如果是,请纠正我:

  1. 要在不依赖 RVO 的情况下实现这一点,必须通过引用返回(再次提醒:请记住,我没有远程资源,只有标量数据成员)。
  2. 通过引用返回使函数调用表达式成为左值,暗示返回的对象不是临时对象,这是不好的,但通过右值引用返回使函数调用表达式成为 xvalue(见 3.10.1),这在我的方法的背景(见 4)
  3. 通过引用返回是危险的,因为对象的生命周期可能很短,但是:
  4. 临时对象可以保证在创建它们的表达式的计算结束之前一直存在,因此:
  5. 如果该右值引用参数所引用的对象是通过引用返回的对象,则使从那些将至少一个右值引用作为其参数的运算符通过引用返回是安全的。所以:
  6. 任何仅使用二元运算符的任意表达式都可以通过在涉及不超过一种类似 PoD 的类型时仅创建一个临时值来评估,并且二元运算本质上不需要临时值(如矩阵乘法)

(通过右值引用返回的另一个原因是,就函数调用表达式的右值而言,它的行为类似于按值返回;并且运算符/函数调用表达式必须是右值才能绑定到随后调用采用右值引用的运算符。如 (2) 中所述,对通过引用返回的函数的调用是左值,因此将绑定到具有签名的运算符T operator+(const T&, const T&),从而导致创建不必要的临时)

我可以通过使用 C 风格的函数方法来实现所需的性能add(Vector4 *result, Vector4 *v1, Vector4 *v2),但是来吧,我们生活在 21 世纪......

总之,我的目标是创建一个向量类,它使用重载运算符实现与 C 方法相同的性能。如果这本身是不可能的,那我想也无济于事。但如果有人能向我解释为什么我的方法注定要失败,我将不胜感激(当然,从左到右的操作员评估问题是我发表帖子的最初原因)。
事实上,我一直在使用“真正的”矢量类,这是一个简化了一段时间,到目前为止没有任何崩溃或损坏的内存。事实上,我从来没有真正返回本地对象作为引用,所以不应该有任何问题。我敢说我所做的是符合标准的。

当然,对原始问题的任何帮助也将不胜感激!

非常感谢所有的耐心再次

0 投票
2 回答
3207 浏览

c++ - C++11 - 区分右值指针

如何将变量区分为编译器构造的字符串?

例如,虽然右值"Hello, World"的类型是const char*. const char*本身并不意味着不能更改指针。char* const指针无法更改,但这不是编译器构造的。

这是否意味着,对于任何包含 aconst char*的容器,数据应该通过 C++ 的移动语义以外的方式复制?有什么方法可以移动编译器构造的字符串而不管所有其他字符串吗?

例如,在 GCC 4.5.2 中,返回类型int而不是返回的方法int&被视为返回int&&。我不知道实际的标准是否应该是这样的,但这就是 GCC 暂时所做的。

编辑:为了澄清,我的意思是应该复制指针指向的实际内存。这意味着必须分配新的内存并且指针中的数据应该被复制到新的位置。

0 投票
2 回答
820 浏览

c++ - 移动语义 std::move

我不太了解这个std::move功能

为什么remove_reference?有人可以给我一个简单的解释吗?

0 投票
2 回答
2375 浏览

c++ - 移动语义 std::move 如何使用它

为什么这段代码不能编译?

错误 C2440:“返回”:无法在“int &&”中转换“int”