【C++】optional的使用(一)

这篇文章介绍下C++17引入的std::optional

为什么要有 optional

一般来说,如果想要一个函数返回“多个”值,C++程序员倾向于使用结构体/类完成这个操作。即定义一个通用的结构体,在函数内部完成装填,然后返回一个实例化的结构体。

#include <iostream>

using namespace std;

struct Out {
   
    string out1 {
    "" };
    string out2 {
    "" };
};

pair<bool, Out> func(const string& in) {
   
    Out o;
    if (in.size() == 0)
        return {
    false, o };
    o.out1 = "hello";
    o.out2 = "world";
    return {
    true, o };
}

int main() {
   
    if (auto [status, o] = func("hi"); status) {
   
        cout << o.out1 << endl;
        cout << o.out2 << endl;
    }
    return 0;
}

(代码来自 https://zhuanlan.zhihu.com/p/64985296

C++17引入了std::optional,介绍如下:

The class template std::optional manages an optional contained value,
i.e. a value that may or may not be present. A common use case for
optional is the return value of a function that may fail. As opposed
to other approaches, such as std::pair<T,bool>, optional handles
expensive-to-construct objects well and is more readable, as the
intent is expressed explicitly. 类模板 std::optional
管理一个可选的容纳值,即可以存在也可以不存在的值。 一种常见的 optional 使用情况是一个可能失败的函数的返回值。与其他手段,如
std::pair<T,bool> 相比, optional 良好地处理构造开销高昂的对象,并更加可读,因为它显式表达意图。

换句话说,一个普通的变量,只有不同的值。而optional相当于在外面套了一层壳,先考虑存不存在值,再考虑值是多少。

使用

对于像我这样的菜鸟来说,optional 的源代码十分复杂的。但是使用起来并不困难,理解上面的含义就行。

  /**
    * @brief Class template for optional values.
    */
  template<typename _Tp>
    class optional
    : private _Optional_base<_Tp>,
      private _Enable_copy_move<
	// Copy constructor.
	is_copy_constructible_v<_Tp>,
	// Copy assignment.
	__and_v<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>,
	// Move constructor.
	is_move_constructible_v<_Tp>,
	// Move assignment.
	__and_v<is_move_constructible<_Tp>, is_move_assignable<_Tp>>,
	// Unique tag type.

可以看到,本质上其实是个模板类,将包裹的类型以模板参数T的方式传入。

初始化

optional几种初始化如下:

    //初始化为空
    optional<int> int_empty;
    //使用有效值初始化(C++其他初始化方法也同样可用)
    optional<int> my_int = 2;
    //使用make_optional
    auto doubleOpt = std::make_optional(10.0);
    auto complexOpt = std::make_optional<std::complex<double>>(3.0, 4.0);
    //使用in_place
    optional<vector<int>> vectorOpt{
   in_place, {
   1, 2, 3}};
    //使用其它optional对象复制/移动构造
    auto optCopied = vectorOpt;

说一下第三点和第四点,就是这个std::make_optionalstd::in_place。我搜到的资料显示这代表直接调用模板T的构造函数,即“完美转发”。

假设我有这么一个类 TestOp:

struct TestOp
{
   
    TestOp() : age(100) {
   }
    int getAge() {
    return age; }

private:
    int age;
};

它有一个无参数的构造函数,但这个构造函数为成员赋默认值。这时,若使用如下写法

    optional<TestOp> test_op;
    cout << test_op.value().getAge() << endl;

会编译失败。因为optional并不会调用TestOp的默认构造函数,只会创建一个空的TestOp对象。
编译失败
这让我非常不理解,因为就算是未传入参数,应该调用T的默认构造函数才对。
你可能想到,如果初始化时直接传入构造函数呢?

    optional<TestOp> test_op{
   TestOp()};

这样写当然没问题,我们将得到包含默认TestOp对象的optional对象。但是在上面的代码中,将先构造出一个TestOp的临时对象,然后调用move函数将这个临时对象“移动”到optional存储的对象中,带来了额外的开销。在这种情况下,我们就只能使用std::in_place/ std::make_optional来“原地”构造optional底层存储的对象。

另一种情况是,TestOp禁用了移动构造和复制构造函数,这时候也只能用std::in_place/ std::make_optional

最后一种必须使用std::in_place/ std::make_optional的情况是,当你需要使用多个参数初始化同一个变量时,比如std::vector。没错,原生的 optional构造函数,并不支持多参数,神奇吧?
6
我猜想多参数的支持会导致歧义。

相关推荐

  1. django基本使用()

    2023-12-17 15:20:02       29 阅读
  2. Flask-SQLAlchemy使用

    2023-12-17 15:20:02       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-17 15:20:02       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-17 15:20:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-17 15:20:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-17 15:20:02       20 阅读

热门阅读

  1. HTML基础:打开网页魔法的大门

    2023-12-17 15:20:02       41 阅读
  2. How to Use the Lsof Command

    2023-12-17 15:20:02       31 阅读
  3. uniapp api uni.request讲解

    2023-12-17 15:20:02       40 阅读
  4. uniapp常用api讲解

    2023-12-17 15:20:02       39 阅读
  5. 【中等】73. 矩阵置零

    2023-12-17 15:20:02       45 阅读
  6. 通过conda search cuda找不到想要的信息,更换channel

    2023-12-17 15:20:02       41 阅读
  7. 使用Go env命令设置Go的环境

    2023-12-17 15:20:02       38 阅读
  8. 小程序生命周期

    2023-12-17 15:20:02       38 阅读
  9. NX 次开发:倒斜角和边缘混合的实现方法

    2023-12-17 15:20:02       38 阅读
  10. 解决pytorch训练的过程中内存一直增加的问题

    2023-12-17 15:20:02       41 阅读