1

参照によって比較される型を作成する方法はありますが、関数で作成できないことを強制します (スタック/削除されたオブジェクトへの参照を防ぎます)。

関数内で「return Error::New(...)」を実行できることに気付くまで、私は以下のエラー型を思いつき、それを誇りに思っていました。問題は h() 関数にあります。

#include <stdio.h>
#include <string.h>
#include <string>

using namespace std;

class Error {
    std::string _str;
    const Error &from;

    Error();
    Error(const char *s)
        : _str(s), from(*this)
    {
    }

public:
    Error(const Error &err)
        : from(err.from)
    {
    }

    static Error New(const char *s) {
        return Error(s);
    }

    bool operator== (const Error &rhs) const {
        return (&from == &rhs.from);
    }

    bool operator!= (const Error &rhs) const {
        return (&from != &rhs.from);
    }

    std::string ToString() {
        return from._str;
    }

public:
    static const Error None;
};

const Error Error::None("none");

// user errors
auto ErrConnect = Error::New("failed to connect");
auto ErrWrite = Error::New("invalid write");

Error f() {
    return ErrConnect;
}

Error g() {
    return Error::None;
}

Error h() {
    return Error::New("test");
}

int main()
{
    printf("ErrConnect == ErrConnect : %d\n", ErrConnect == ErrConnect);
    printf("ErrConnect == ErrWrite : %d\n", ErrConnect == ErrWrite);
    printf("f() == ErrConnect : %d\n", f() == ErrConnect);
    printf("f() == ErrWrite : %d\n", f() == ErrWrite);
    printf("f() != ErrConnect : %d\n", f() != ErrConnect);
    printf("f() != ErrWrite : %d\n", f() != ErrWrite);
    printf("f() == Error::None : %d\n", f() == Error::None);
    printf("f() != Error::None : %d\n", f() != Error::None);
    printf("g() == Error::None : %d\n", g() == Error::None);
    printf("g() != Error::None : %d\n", g() != Error::None);
    printf("f().ToString() : %s\n", f().ToString().c_str());
    printf("ErrConnect.ToString() : %s\n", ErrConnect.ToString().c_str());

    auto err = f();
    auto err2 = err;
    auto err3 = err2;
    printf("err3 == ErrConnect : %d\n", err3 == ErrConnect);

    auto err4 = h();
    printf("err4 from h() : %s\n", err4.ToString().c_str());
}
4

3 に答える 3

1

これを実装する最良の方法は、静的 std::atomic カウンター (具体的には、_uint_fast64_t が最適と思われる) を使用することであることがわかりました。そこから、Error(const char *s) コンストラクターと std:: の各エラー タイプに対して ID が作成されます。 atomic::fetch_add() を使用してフェッチ/インクリメントします:

http://en.cppreference.com/w/cpp/atomic/atomic

唯一の欠点は、これらが C++11 にのみ存在することです (Visual Studio 2012; 古いディストリビューションを除いて、Linux は問題になりません)。

于 2013-04-29T14:49:38.733 に答える
0

私はUUIDを使用することになりました:

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>

using namespace std;

class Error {
    std::string msg;
    boost::uuids::uuid tag;

public:
    Error(const char *s)
        : msg(s), tag(boost::uuids::random_generator()())
    {
    }

    Error(const Error &rhs)
        : msg(rhs.msg), tag(rhs.tag)
    {
    }

    Error(Error &&rhs)
        : msg(std::move(rhs.msg)), tag(rhs.tag)
    {
    }

    Error &operator=(const Error &rhs) {
        msg = rhs.msg;
        tag = rhs.tag;
        return *this;
    }

    bool operator==(const Error &rhs) const {
        return (tag == rhs.tag);
    }

    bool operator!=(const Error &rhs) const {
        return (tag != rhs.tag);
    }

    std::string ToString() {
        return msg;
    }

public:
    static const Error None;
};

const Error Error::None("none");

// user errors
auto ErrConnect = Error("failed to connect");
auto ErrWrite = Error("invalid write");
于 2013-04-26T15:37:08.080 に答える