通过引用传递 std::optional<T> 是否真的节省了复制?

Does passing an std::optional<T> by reference actually save copying?

我知道标准不支持 std::optional<T&>。这个问题是关于传递 std::optional<T>& 是否有任何性能优势

此处转载示例代码 (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<T>,但在 DoStuffRef 中不存在,所以我怀疑是的,传递了一个 optional通过引用保存一些复制

感谢帮助!

如果您通过实际 std::optional<std::string> 那么是的,不会有副本。但是,如果您只传递 std::string,则必须首先构造临时可选,从而生成字符串的副本。

DoStuffRef 当参数已经是 std::optional<std::string> 时保存一个额外的副本(如您的示例)。

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