C++ 将API use std::字符串作为错误代码返回是一种不好的做法吗?

C++ 将API use std::字符串作为错误代码返回是一种不好的做法吗?,c++,string,error-handling,C++,String,Error Handling,在向用户交付API时,您通常需要声明错误代码(通常为int),之后您通常需要提供一个函数,将int错误代码转换为std::string,以便能够以智能方式向用户报告错误 我找到了一些关于如何以编程方式维护int/std::string映射的帖子,如下所示: 现在,我想知道,为什么不直接返回std::string而不是int?空字符串将意味着没有错误,其他任何内容将意味着错误+提供人类可读的消息 很明显,我们假设您不关心内存使用和性能(您的API没有经常调用的函数,执行时间也不重要) 如果您需要客

在向用户交付API时,您通常需要声明错误代码(通常为
int
),之后您通常需要提供一个函数,将
int
错误代码转换为
std::string
,以便能够以智能方式向用户报告错误

我找到了一些关于如何以编程方式维护
int
/
std::string
映射的帖子,如下所示:

现在,我想知道,为什么不直接返回
std::string而不是
int
?空字符串将意味着没有错误,其他任何内容将意味着错误+提供人类可读的消息

很明显,我们假设您不关心内存使用和性能(您的API没有经常调用的函数,执行时间也不重要)

如果您需要客户端能够以编程方式执行某些特定操作,则可以将错误代码声明为常量。但是您不再需要任何
int
std::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 ;
    }
}
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;
    }
}
实施:

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 ;
    }
}
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;
    }
}
API用户可以执行以下操作:

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 ;
    }
}
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;
    }
}
intmain()
{
std::string error=openFile(“file.txt”);
if(error.empty())
{

std::cout这可能对用户有用,但对开发人员没有用处

如果出现任何错误,我想很容易找到造成错误的地点。你能保证邮件不会改变,这样以后的搜索会指向正确的地点吗?使用enums更容易获得这一点-更改邮件不会造成任何实际伤害


您不应低估性能问题。比较、复制、分配—it成本。如果您真的不在乎,只需创建一个包含错误代码和字符串消息的结构。或者引发异常。

为什么不进一步进行一个阶段并做正确的事(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;
   }

缺点:每次返回时为字符串分配内存并复制字符串。未向最终用户显示字符串的API用户将不得不为其未使用的功能支付性能费用。缺点-字符串比较与两个整数相等相比成本较高用户可能会尝试使用原始字符串而不是global,然后你就不能更改消息(比如输入错误,…)@zenith:正如前面提到的,性能和内存使用在这里不是什么大问题。更难国际化。例外情况对库本身来说很好(
openFile
)但是对于库用户来说是一个真正的痛苦,必须总是
尝试
/
捕获
每个函数调用….@jpo38异常和RAII的全部基础是,您不需要捕获每个异常。您可以在堆栈框架中捕获它们,然后处理它们。如果在main()中有了一个通用的catch,所有代码<代码> STD::异常和然后是。痛苦是返回状态代码的库,因为这意味着用户代码变得错误检查,隐藏逻辑和创建不必要的资源清理逻辑。@ JP38从C++标准体和语言的创建者:这使我感到:(的确,它不需要调用方编写更多的代码…@jpo38奇妙:)又有一个开发人员生成了优秀的、可维护的代码。欢迎来到光明的新世界!(更新了答案,提供了一个正确异常处理的完整可编译示例)