2012-08-05 65 views
1

我正在创建一个库。我想制作一个固定长度的字符串类。投掷异常与返回结果代码

#include <string> 
#include <iostream> 

#define OK 0 
#define TOO_LONG 1 
#define UNALLOWED_CHARACTERS 2 

struct MyString { 
    MyString(int l) 
     : m_length(l) { } 
    struct exception { 
     exception(int t, MyString *p) 
      : type(t), ptr(p) { } 
     int type; 
     MyString *ptr; 
    }; 
    int set(const std::string& name); 
    void set2(const std::string& name) throw(exception); 

    std::string m_str; 
    int m_length; 
}; 

int MyString::set(const std::string& s) 
{ 
    if(s.size() > 64) { 
     return TOO_LONG; 
    } else if(s.find('~') != std::string::npos) { 
     return UNALLOWED_CHARACTERS; 
    } else { 
     m_str = s; 
     return OK; 
    } 
} 

void MyString::set2(const std::string& s) throw(exception) 
{ 
    if(s.size() > m_length) { 
     throw exception(TOO_LONG, this); 
    } else if(s.find('~') != std::string::npos) { 
     throw exception(UNALLOWED_CHARACTERS, this); 
    } else { 
     m_str = s; 
    } 
} 

int main() 
{ 
    using namespace std; 
    //OPTION 1 
    { 
     MyString s1(10); 
     MyString s2(10); 
     int code; 

     code = s1.set("abcdefghijX"); 
     switch(code) { 
     case TOO_LONG: 
      //handle <-- 
      break; 
     case UNALLOWED_CHARACTERS: 
      //handle 
      break; 
     default: 
      //ok! 
      break; 
     } 

     code = s2.set("abcdefghi~"); 
     switch(code) { 
     case TOO_LONG: 
      //handle 
      break; 
     case UNALLOWED_CHARACTERS: 
      //handle <-- 
      break; 
     default: 
      //ok! 
      break; 
     } 
    } 

    //OPTION 2 
    { 
     MyString s1(10); 
     MyString s2(10); 
     try { 
      s1.set2("abcdefghijX"); 
      s2.set2("abcdefghi~"); 

     } catch(MyString::exception &e) { 
      cerr << "MyString::exception: "; 
      auto p = e.ptr; 
      if(p == &s1) cerr << "s1 "; 
      else if(p == &s2) cerr << "s2 "; 
      switch(e.type) { 
       case TOO_LONG: cerr << "too long"; break; 
       case UNALLOWED_CHARACTERS: cerr << "unallowed characters"; break; 
      } 
      cerr << endl; 
     } 

    } 
} 

我不知道我应该使用MyString :: set()的哪个版本。这种情况下的约定是什么?为了演示目的,我在本例中使用了STL。

+1

这是一个表面上很好的问题,但实际上会引起很多争论。这是那些宗教问题之一。 – djechlin 2012-08-05 15:57:55

+1

另外,请勿使用投掷规格。我只能假设它们是在运行时检查的白痴原因,并且会导致std :: unexpected并因此被破坏(如果被违反)(在调试/开发设置中有用,但不在生产环境中),这实际上是相反的你想要做什么例外。 – djechlin 2012-08-05 16:00:06

+1

@djechlin好点。而且,异常规范在C++ 11中已弃用。 – juanchopanza 2012-08-05 16:39:00

回答

1

它是模仿的标准库函数的行为是一个好主意,除非一个有特定的理由。顺便说一下,自tr1以来,STL有一个固定长度的字符串类内置。让我们看看它的作用。唯一的示例实现我是得心应手的Visual C++ 2010

 

std::tr1::array<int,5> arry; 
arry[10] = 42; // Oopsie. There is no element 10. 
 

编译和运行的“调试”版本,我得到一个断言失败。当编译为“发布”的时候,这个攻击性声明悄悄地......没有任何东西。它优化不存在。好吧,也许这并不总是人们想要的。忘记我所说的模仿STL,或者至少是微软的实现。意识列车继续...

我认为这是公平的说,如果程序试图设置超出范围的单元格,这是程序中的逻辑错误。在关键任务软件中,可能有一个好主意,让代码可以处理这样的情况并从中恢复,同时尽可能确保它永远不会发生。

所以答案是,抛出std :: out_of_range类型的异常。

所以那里。

+0

好吧,我刚刚阅读了一些关于标准例外的信息,它们适合我的需求。我只是认为_std :: length_error_更精确一些,因为我不能接受'mapObject.name ='这样的语句,这个名字对于地图名称来说太长!“('name'是一个属性)。 – cubuspl42 2012-08-10 14:59:20

1

通常在C++中,建议使用异常来指示在当前上下文中不可恢复的错误。但这取决于目的。您可能希望在没有例外情况的嵌入式环境中编译库(为了提高效率),那么您必须使用返回代码。

它很容易将使用返回码的API包装为使用异常的API,但反之亦然。

编辑:

一些更多的理由为什么它可能是有意义的不使用异常处理:

异常处理通常带来额外的信息被放置在调用栈+一些性能需要约try/catch块建立和检查这些信息的惩罚。

参见:performance of C++0x exceptions

+0

如果错误是“不可恢复的”,则不需要错误代码或抛出异常。打电话给()并完成它。 – 2012-08-09 03:44:53

+0

尝试块是为了“所有这些都必须完成,否则就是放松堆栈并让我回到catch-block”。通常情况确实例外。然而,我记得在我所有几十年的编程中,只有一个应用程序,当堆栈很深并且不再需要帧时,完成任务是正常的。不寻常的情况是跑完成(然后放弃失败)。对于该功能,抛出(“成功”)是期望的结果,并且是正常的。 – 2012-08-09 03:56:19

+0

@JiveDadson我已经改变了一些措辞,我认为这是更全面的,我的意思是'不可恢复的'。 – 2012-08-09 07:50:43