问题标签 [nrvo]
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++ - 将结构像 std::list> 返回时被复制?
我有一个函数,可以从给定的字符串中提取键值列表,其中每个键/值对由 a 表示std::pair
,该函数具有如下签名:
如果我的实现看起来像:
1) 我不希望发生任何副本,我想知道 RVO/NRVO 是否会应用于列表中的对和持有它们的列表。
2)如果在这种情况下会发生复制,那么在不复制的情况下实现这一点的替代数据结构是什么?我可以想到一个使用 的解决方案unique_ptr<unorder_map<>>
,但就我而言,我只需要支持列表中对的迭代,不需要支持通过它们的键查找值,因此我想避免在插入过程中进行不必要的哈希计算。
3) 我知道 RVO/NRVO 是依赖于编译器的行为,有什么方法可以验证这些行为是否容易发生?
c++ - 如果没有定义析构函数,为什么不会发生返回值优化?
我希望从这个测试程序中看到来自命名返回值优化 (NRVO) 的复制省略,但它的输出是“地址不匹配!” 所以 NRVO 没有发生。为什么是这样?
笔记:
如果通过启用
#if
上述方法定义了析构函数,则 NRVO 确实会发生(并且在其他一些情况下也会发生,例如定义虚拟方法或添加std::string
成员)。没有定义任何方法,所以 A 是一个 POD 结构,或者在最近的术语中是一个琐碎的 class。我在上面的链接中没有看到明确的排除。
添加编译器优化(添加到一个更复杂的示例,而不仅仅是简化为空程序!)没有任何区别。
查看第二个示例的程序集表明,当我期望强制返回值优化 (RVO) 时,甚至会发生这种情况,因此上面的 NRVO 并没有通过获取 in 的地址来
fn_a
阻止fn()
。x86-64 上的 Clang、GCC、ICC 和 MSVC 显示相同的行为,表明此行为是故意的,而不是特定编译器中的错误。
c++ - 如果一个变量被分配了一个函数返回的对象,它是复制还是就地创建?
我的 CPP 文件中有类似的东西来初始化任何类之外的对象。我已经简化了它,但关键是正在进行一些复杂的初始化,但我想要创建一个实例:
ret
我的问题是,由于编译器的聪明,这个对象是否被复制o
或就地创建?“就地创造”可能有一个恰当的术语——安置?
如果相关的话,我正在使用 C++17(即答案取决于语言版本)。是否有明确的答案,或者这可能是特定于编译器的优化?
c++ - 为什么这里不执行 NRVO(多次返回)?
MyString ret
在以下方法中不执行 NRVO 。默认构造的 MyString ( return {};
) 直接构造到目标中, ret 被移动构造到目标中。
如果在其主体中MyString ret{length + 1};
的 if 语句之上return{};
,我会很清楚为什么它不能直接构造到目标中:如果是,则返回默认构造的 MyString 对象,销毁ret
将是必需的,并且默认构造的对象将取代它。这是不可取的。但是,在这种情况下,MyString ret
不能直接构造到目标中的根本原因是什么?在代码中构造时,众所周知该函数不会return {};
.
我确定我在这里忽略了一些东西。任何帮助是极大的赞赏!
编辑:这是@rustyx 建议的最小可重复示例:
这打印:
c++ - 可以在调试版本中关闭 NRVO 吗?
在程序中如下
我希望命名返回值优化发生在 foo() 中,因此不会调用复制或移动构造函数。确实 gcc 和 clang 打印“0”。
但是调试配置中的 Visual Studio 2019 打印“02”。是否允许编译器在调试版本中避免使用 NRVO?
c++ - RVO 是预期的,但没有发生
我有以下连接池的基本实现。在非常高的级别上,它为客户端提供了一种从池中获取打开连接的安全方式,或者如果所有连接当前都在使用中,则打开一个新连接。结构是连接的Connection
低级实现。ClientConnection
struct 是一个包装器,因此Connection
客户端只能有限地访问对象,并为使用 RAII 将对象返回到池中Connection
提供一种安全的方式。Connection
打电话时Pool::getNewConnection()
,我预计 NRVO 会发生,但它没有发生,我终生无法弄清楚原因。我希望只调用一次析构函数,因为我创建了ClientConnection
inmain()
然后它被销毁了。但是,发生的情况是在Pool::getNewConnection()
,然后移动到对象的内存中main()
,因此调用了2个析构函数。
g++ -std=c++17 -O0 -g -o main main2.cpp
使用和构建g++ -std=c++17 -O3 -g -o main main2.cpp
输出是: