【问题标题】:Does passing an std::optional<T> by reference actually save copying?通过引用传递 std::optional<T> 是否实际上保存复制?
【发布时间】:2021-11-15 12:46:58
【问题描述】:

我知道标准不支持std::optional&lt;T&amp;&gt;。这个问题是关于通过std::optional&lt;T&gt;&amp;是否有任何性能优势

此处转载示例代码 (https://godbolt.org/z/h56Pj6d6z)

#include <ctime>
#include <iomanip>
#include <iostream>
#include <optional>

void DoStuff(std::optional<std::string> str) {
    if (str) std::cout << "cop: " << *str << std::endl;
}

void DoStuffRef(const std::optional<std::string>& str) {
    if (str) std::cout << "ref: " << *str << std::endl;
}

int main() {
    std::optional<std::string> str = {};
    DoStuff(str);
    DoStuffRef(str);
    str = "0123456789012345678901234567890123456789";
    DoStuff(str);
    DoStuffRef(str);
}

(我的实际用例对于复杂的用户定义类型是可选的,但我希望长字符串在编译器方面也能做到这一点)

在这种情况下,与DoStuff 相比,DoStuffRef 是否实际上节省了任何复制工作?

我试图查看 Godbolt 输出,但我不知道足够的汇编来确定。我确实看到在DoStuff 的情况下,似乎创建了一个临时std::optional&lt;T&gt;,而DoStuffRef 中不存在所以我怀疑是的,通过引用传递optional 保存一些复制

感谢您的帮助!

【问题讨论】:

  • 是的,当可选项实际包含字符串时,您会保存一份副本。

标签: c++ stdoptional


【解决方案1】:

如果您传递实际的std::optional&lt;std::string&gt;,那么是的,不会有副本。但如果你只传递std::string,那么必须先构造临时可选,从而生成字符串的副本。

【讨论】:

  • 所以在这种情况下,当我将str 分配给一个字符串值并传递它时,由于str 仍然是std::optional&lt;std::string&gt; 类型,我应该使用DoStuffRef 保存一个副本对?
  • 我认为在 C++17 中它不会创建副本,因为 en.cppreference.com/w/cpp/utility/optional/optional 中的“(8)”
  • @resnet 完全正确。
  • @alfC 当然,如果std::string 是右值,如果是副本,它将是一个移动,但仍会构建临时的。
【解决方案2】:

DoStuffRef 在参数已经为 std::optional&lt;std::string&gt; 时保存一个额外的副本(如您的示例中所示)。

但是,如果你直接传递一个std::string,那么如果这两种情况都应该构造一个std::optional,涉及到字符串的复制/移动构造函数。

【讨论】:

    猜你喜欢
    • 2021-05-20
    • 2010-10-10
    • 2019-05-10
    • 1970-01-01
    • 2012-07-08
    • 2023-03-09
    相关资源
    最近更新 更多