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 进行演示。

4

2 回答 2

1

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

使用返回码将 API 包装到使用异常的 API 很容易,但反之则不行。

编辑:

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

try/catch异常处理通常会引入有关需要放置在调用堆栈中的块的附加信息+ 一些性能损失来构建和检查这些信息。

另请参阅:C++0x 异常的性能

于 2012-08-05T15:34:01.877 回答
1

模仿标准库函数的行为是一个好主意,除非有特定的理由不这样做。顺便说一句,从 tr1 开始,STL 内置了一个固定长度的字符串类。让我们看看它做了什么。我手头的唯一示例实现是 Visual C++ 2010。


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

当编译并作为“调试”版本运行时,我得到一个断言失败。当为“Release”编译时,冒犯性的声明悄悄地做......什么都没有。它在不存在时就被优化了。好吧,也许这并不总是人们想要的。忘记我所说的模仿 STL,或者至少是微软的实现。意识列车继续……

我认为可以公平地说,如果程序试图设置超出范围的单元格,那是程序中的逻辑错误。在任务关键型软件中,最好有适当的代码来处理这种情况并从中恢复,同时努力确保它永远不会、永远不会发生。

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

所以在那里。

于 2012-08-09T03:38:24.573 回答