【cpp】std::opcional

Endereço original

Introdução

float divide(float a, float b)
{
    
    
	if (b == 0)
	{
    
    
		return ?;
	}
	return a / b;
}

Aqui está uma função de divisão como exemplo: quando b é 0, é obviamente uma exceção de divisão, mas como retornar esse status ao chamador?

Os métodos comuns incluem o seguinte

  • Lança uma exceção. Ao dividir por 0, uma exceção relacionada é lançada. O chamador captura a exceção.
  • O retorno de um valor especial (-1, infinito, nullptr) precisa ser acordado com o chamador e a semântica não é muito clara.
  • Tipos opcionais.Este é um tipo seguro e mais expressivo.

std::optionalAdicionados no C++ 17, os padrões C++ anteriores podem ser boost::optionalobtidos por meio do . #include <optional>Você pode usar esse tipo em C++17 .

O que está std::optionalencapsulado ainda é um tipo de valor e pode ser copiado. std::optionalNão há necessidade de solicitar memória no heap.

Quando usar

Normalmente, pode-se usar std::optionalencapsulamento nesses cenários

  • Precisa de melhor representação de tipos anuláveis
    • Em vez disso, use valores especiais (-1, nullptr, NO_VALUE ou outro)
    • Por exemplo, alguns valores podem existir ou não, mas precisamos saber se eles existem. Por exemplo, ao contar idades, pode não haver idade em alguns dados. Nesse caso, podemos usar representação std::optional<int>.
  • Retorna um resultado de falha de execução
    • Por exemplo, quando a divisão por 0 está errada e o valor correto não pode ser obtido.
  • Ao carregar recursos preguiçosamente
    • Por exemplo, um tipo de recurso não possui um construtor padrão, mas o trabalho de construção é relativamente grande e pode ser definido usando-o std::optional<Resource>e carregado quando necessário.
    • Ao passar parâmetros

Exemplo Básico

std::optional<std::string> UI::FindUserNick()
{
    
    
    if (nick_available)
        return {
    
     mStrNickName };

    return std::nullopt; // same as return { };
}

// use:
std::optional<std::string> UserNick = UI->FindUserNick();
if (UserNick)
    Show(*UserNick);

Criação

// empty:
std::optional<int> oEmpty;
std::optional<float> oFloat = std::nullopt;

// direct:
std::optional<int> oInt(10);
std::optional oIntDeduced(10); // deduction guides

// make_optional
auto oDouble = std::make_optional(3.0);
auto oComplex = make_optional<std::complex<double>>(3.0, 4.0);

// in_place
std::optional<std::complex<double>> o7{
    
    std::in_place, 3.0, 4.0};

// will call vector with direct init of {1, 2, 3}
std::optional<std::vector<int>> oVec(std::in_place, {
    
    1, 2, 3});

// copy/assign:
auto oIntCopy = oInt;

Obter valor

// by operator*
std::optional<int> oint = 10;
std::cout<< "oint " << *opt1 << '\n';

// by value()
std::optional<std::string> ostr("hello");
try
{
    
    
    std::cout << "ostr " << ostr.value() << '\n';  
}
catch (const std::bad_optional_access& e)
{
    
    
    std::cout << e.what() << "\n";
}

// by value_or()
std::optional<double> odouble; // empty
std::cout<< "odouble " << odouble.value_or(10.0) << '\n';

Uma abordagem segura é determinar se está vazio ao acessar

    // compute string function:
    std::optional<std::string> maybe_create_hello();  
    // ...  

    if (auto ostr = maybe_create_hello(); ostr)
        std::cout << "ostr " << *ostr << '\n';  
    else  
        std::cout << "ostr is null\n";

Modificar valor

#include <optional>
#include <iostream>
#include <string>

class UserName
{
    
    
public:
    explicit UserName(const std::string& str) : mName(str)
    {
    
     
        std::cout << "UserName::UserName(\'";
        std::cout << mName << "\')\n"; 
    }
    ~UserName() 
    {
    
    
        std::cout << "UserName::~UserName(\'";
        std::cout << mName << "\')\n"; 
    }

private:
    std::string mName;
};

int main()
{
    
    
    std::optional<UserName> oEmpty;

    // emplace:
    oEmpty.emplace("Steve");

    // calls ~Steve and creates new Mark:
    oEmpty.emplace("Mark");


    // reset so it's empty again
    oEmpty.reset(); // calls ~Mark
    // same as:
    //oEmpty = std::nullopt;

    // assign a new value:
    oEmpty.emplace("Fred");
    oEmpty = UserName("Joe"); 
}

Guess you like

Origin blog.csdn.net/qq_30340349/article/details/132969322