Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我在滥用性病吗 std::optional如何适合我的代码?_C++_C++17_Stdoptional - Fatal编程技术网

C++ 我在滥用性病吗 std::optional如何适合我的代码?

C++ 我在滥用性病吗 std::optional如何适合我的代码?,c++,c++17,stdoptional,C++,C++17,Stdoptional,我的代码包含许多函数,大致如下所示: bool GetName(_Out_ string& strRes) { // try to get/calculate the value // value may also be empty // return true on success, false otherwise. } 现在我知道了,我只需编写代码: std::optional<std::string> GetName() 在这个函数中,我“被迫”提

我的代码包含许多函数,大致如下所示:

bool GetName(_Out_ string& strRes)
{
   // try to get/calculate the value
   // value may also be empty
   // return true on success, false otherwise.
}
现在我知道了,我只需编写代码:

std::optional<std::string> GetName()
在这个函数中,我“被迫”提供两个容器,因为我想区分:

  • 在数据库中找到密钥,该密钥为空。此键将位于
    mapKeyValue
  • 在数据库中找不到密钥。此键将不在
    mapKeyValue
  • 但是使用
    可选的
    我可以:

    void GetValuesFromDB(map<string,std::optional<string> > mapKeyValue);
    
    void GetValuesFromDB(map-mapKeyValue);
    

    我相信我们把
    这个词理解得太字面了

    我真的支持可以使用
    std::optional


    C++标准委员会可以轻易地决定<代码> STD::可选< /COD>,<代码> STD::可空< <代码> >

    std::optional
    是一个表示“可选”值的类。如果您有一个案例,您可能会产生一个值,也可能不会,那么可选是一种方法。性能价格可以忽略不计(附加条件,如果值在这里,可能实际上会减慢速度,但由于值是可选的,您将始终需要在某个地方进行检查,如果值仍然存在),真正的价格是内存:

    printf("%d\n", (int)sizeof(std::string));
    printf("%d\n", (int)sizeof(std::optional<std::string>));
    
    在64位上

    所以,如果你在一个结构中做了,比如说:

    struct A {
        std::optional<std::string> a, b, c, d, e, f, g, h;
    };
    
    struct B {
        std::string a, b, c, d, e, f, g, h;
        unsigned char has_a : 1,
            has_b : 1,
            has_c : 1,
            has_d : 1,
            has_e : 1,
            has_f : 1,
            has_g : 1,
            has_h : 1;
    };
    
    这可能真的很痛。但通常不会


    那么你是在滥用自由选择权吗?如果您使用optional来表示错误,那么根据错误的上下文,您可能会选择稍微“是”。但这要视情况而定。如果代码清晰性更重要的是信号,那么该函数没有产生值,而不是为什么它没有产生值,那么当然,去做吧。

    我认为这是一种滥用

    我将重写为
    std::string getName()const
    (依赖于现在所需的RVO),如果发生了不正常的情况(例如某种获取错误),则抛出异常(来自
    std::exception
    )的自定义类型)。空白名称是否为错误取决于您的应用程序

    如果不允许使用异常,则依赖于表单的C样式错误传播

    int getName(std::string*) const
    
    因为使用
    std::optional
    会使实际错误不透明(除非将错误
    struct
    嵌入到当前线程中)

    我在滥用性病吗

    也许吧

    std::optional
    的预期语义是表示某些内容是可选的。也就是说,如果事物不存在,那是正常的,而不是错误

    如果您的方法失败,它将返回一个空的可选值以指示失败。但是这个失败是否也是一个错误取决于调用代码所期望的语义,您没有显示或描述:如果可选结果为空,您会怎么做

    比如说,

    auto name = GetName();
    if (!name) { diediedie(FATAL_ERROR); }
    
    表明该名称实际上不是可选的。如果您不能(如您所说)在这里使用异常,那么
    variant
    方法似乎更清晰,并且还允许您的失败函数传达异常中可能出现的失败原因

    相反地

    auto name = GetName();
    if (name) {
      cout << "User is called " << *name << '\n';
    } else {
      cout << "User is anonymous\n";
    }
    
    auto name=GetName();
    如果(姓名){
    
    cout我将试着做一个简短的回答:

    在它的核心,一个
    std::optional
    只是一个带有bool的值(ala.
    std::pair
    )。请记住,原始指针(在大多数上下文中)也是可选的

    通常使用以下经验法则:

  • 对错误/故障状态/异常情况等使用异常
  • 仅在需要时使用可选功能!除非您是“第二方或第三方”图书馆作者,否则不要计划使用optionals进行futureproof
  • 如果您希望得到结果,请不要使用可选选项
  • 当某些东西实际上是可选的时,使用optional-例如,一个可能最终找到0或1个结果的函数返回一个可选结果是有意义的。一个可能找到多个结果的函数自然会倾向于返回一个结果容器
  • 关于字符串,有时更倾向于使用空字符串(主要是因为简单),而不是
    std::optional
    ,有时则相反

  • 当计算失败时,为什么不使用异常?在预期结果时不应使用异常。具有C++风格的错误检查的许多C++函数看起来像代码气味。如果这些函数在成功时返回false,以指示没有检索到任何值(即使没有发生错误)。然后,
    std::optional
    可能是一个合理的选择。唯一的缺点是,一旦成功,您将始终创建一个新对象,而不是重用作为参数传递的现有对象。这可能会导致显著的性能损失。如果您想知道e的原因,另一个选项是类似于
    std::variant
    错误。“我没有声明如果GetName返回false,则表示我的流中存在某种错误。当GetName返回false时,我可以生成一个随机名称,或者忽略当前迭代。”因此,这是一个错误,您知道从该错误中恢复的适当方法。空名称不是错误的标志。它是一个有效的、可行的值。任何字符串值都是有效的,除非计算/获取失败。此外,我们不处理异常,从技术上讲也不能处理异常。它可能是错误的/糟糕的,但我认为一个约束。@ IdSuMu是一个在你的问题中没有被指定的约束。是的,在C中,但是这是C++。你需要函数的用户通过指针传递STD::String,它表示这个函数的STD::String参数是可选的。你不发出信号,函数可能会或可能不填充这个参数。由于一个异常不是“C++方式”。返回一个可选的(可能是有效的)根本不存在的东西是完全好的。在禁止异常的情况下,没有理由去C++中的“完全C”。@ RADOS.AW的建议仍然是一个很好的建议。你做什么?
    int getName(std::string*) const
    
    auto name = GetName();
    if (!name) { diediedie(FATAL_ERROR); }
    
    auto name = GetName();
    if (name) {
      cout << "User is called " << *name << '\n';
    } else {
      cout << "User is anonymous\n";
    }