通过引用传递 std::optional<T> 是不是实际上保存复制?
Posted
技术标签:
【中文标题】通过引用传递 std::optional<T> 是不是实际上保存复制?【英文标题】:Does passing an std::optional<T> by reference actually save copying?通过引用传递 std::optional<T> 是否实际上保存复制? 【发布时间】:2021-11-15 12:46:58 【问题描述】:我知道标准不支持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
保存一些复制
感谢您的帮助!
【问题讨论】:
是的,当可选项实际包含字符串时,您会保存一份副本。 【参考方案1】:如果您传递实际的std::optional<std::string>
,那么是的,不会有副本。但如果你只传递std::string
,那么必须先构造临时可选,从而生成字符串的副本。
【讨论】:
所以在这种情况下,当我将str
分配给一个字符串值并传递它时,由于str
仍然是std::optional<std::string>
类型,我应该使用DoStuffRef
保存一个副本对?
我认为在 C++17 中它不会创建副本,因为 en.cppreference.com/w/cpp/utility/optional/optional 中的“(8)”
@resnet 完全正确。
@alfC 当然,如果std::string
是右值,如果是副本,它将是一个移动,但仍会构建临时的。【参考方案2】:
DoStuffRef
在参数已经为 std::optional<std::string>
时保存一个额外的副本(如您的示例中所示)。
但是,如果你直接传递一个std::string
,那么如果这两种情况都应该构造一个std::optional
,涉及到字符串的复制/移动构造函数。
【讨论】:
以上是关于通过引用传递 std::optional<T> 是不是实际上保存复制?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 std::optional<T>::emplace 的第二个重载
如何优雅处理多参数返回/无参数返回——std::optional
是否有一种紧凑的方法可以使 std::optional<T>::value_or 对 T 的成员变量起作用