当前位置:  开发笔记 > 编程语言 > 正文

将API使用std :: string作为错误代码返回是不好的做法吗?

如何解决《将API使用std::string作为错误代码返回是不好的做法吗?》经验,为你挑选了1个好方法。

在向您提供API时,您经常需要声明错误代码(最常见的是int),之后您经常需要提供一个转换int错误代码的函数,std::string以便能够以智能方式向用户报告错误.

我发现了一些关于如何以编程方式维护int/ std::string映射的帖子,如下所示:将错误代码映射到C++中的字符串

现在,我在想,为什么不简单地回归std::string而不是int?空字符串意味着没有错误,其他任何意味着错误+提供人类可读消息.

我们显然假设您不关心内存使用和性能(您的API通常不会调用函数,执行时间并不重要).

如果您需要客户端能够以编程方式执行某些特定操作,则可以将错误代码声明为常量.但是,你不需要任何intstd::string映射了.例如,它将是:

宣言:

static const std::string successMessage;
static const std::string fileDoesNotExistMessage;
static const std::string internalErrorMessage;

std::string openFile( const std::string& fileName );

执行:

static const std::string successMessage = "";
static const std::string fileDoesNotExistMessage = "File does not exist";
static const std::string internalErrorMessage = "Internal error";

std::string openFile( const std::string& fileName )
{
    if ( ... ) // test file existance
    {
        if ( ... ) // internal tests
            return internalErrorMessage;
        else
            return successMessage;
    }
    else
    {
        return fileDoesNotExistMessage ;
    }
}

然后API用户可以:

int main()
{
    std::string error = openFile( "file.txt" );
    if ( error.empty() )
    {
        std::cout << "File was successfully opened" << std::endl;
    }
    else if ( error == fileDoesNotExistMessage )
    {
        // specific error handling
    }
    else
    {
        std::cout << "Unable to open file, error reported is " << error << std::endl;
    }
}

好处:

没有int/有std::string破坏映射的风险

易于添加错误代码

易于维护

必须有不满,因为我不知道使用这种方法的开源库...任何想法为什么?



1> Richard Hodg..:

为什么不再进一步做正确的事(tm)?

报告异常错误.这就是他们的目的.

例:

struct file_does_not_exist : std::runtime_error
{
  using std::runtime_error::runtime_error;
};

struct internal_error : std::runtime_error
{
  using std::runtime_error::runtime_error;
};

void openFile( const std::string& fileName )
{
    if (!fileExists())
      throw file_does_not_exist(fileName + " does not exist");

    if (!internal_tests(fileName))
      throw internal_error("internal tests failed");

    doLogic();
}

用户代码现在变为:

   try {
     openFile("xyz.txt");
     do_other_logic();
     ...
   }
   catch(const std::exception& e)
   {
      std::cerr << "failed because: " << e.what() << std::endl;
   }

一个完整的例子,说明了为什么例外正确的事情

#include 
#include 
#include 
#include 
#include 

// define our program's exceptions, deriving from standard types
struct failed_to_open : std::runtime_error
{
    using std::runtime_error::runtime_error;
};

struct database_op_failed : std::runtime_error
{
    using std::runtime_error::runtime_error;
};

struct user_update_failed : std::runtime_error
{
    using std::runtime_error::runtime_error;
};

// copied from cppreference.com
void print_exception(const std::exception& e, int level =  0)
{
    std::cerr << std::string(level, ' ') << "exception: " << e.what() << '\n';
    try {
        std::rethrow_if_nested(e);
    } catch(const std::exception& e) {
        print_exception(e, level+1);
    } catch(...) {}
}


void open_file(std::fstream& f, const std::string& filename)
{
    throw failed_to_open(std::string("failed to open file " + filename));
}


struct database_connection
{
    database_connection()
    try {
        open_file(_file, "database.txt");
    }
    catch(...) {
        std::throw_with_nested(database_op_failed("database failed to create"));
    }


    std::fstream _file;
};

// note the use of function try blocks coupled with
// throw_with_nested to make exception handling *clean and easy*
void update_user_age(const std::string& name, int newage)
try {
    database_connection d;
    // d.update_record(...)
    // ... RAII
}
catch(...) {
    std::throw_with_nested(user_update_failed("failed to update user " + name
                                                + " to age " + std::to_string(newage)));
}


// only one try/catch in the whole program...
int main()
{
    try {
        update_user_age("bob", 30);

        // ... lots more log here with no need to check errors

    }
    catch(const std::exception& e) {
        // ...which completely explains the error
        print_exception(e);
        return(100);
    }
    return 0;
}

预期产量:

exception: failed to update user bob to age 30
 exception: database failed to create
  exception: failed to open file database.txt

推荐阅读
周扒pi
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有