如何使一个类型易于通过引用进行比较
How to make a type that is easily compared by reference
如何创建一个通过引用进行比较的类型,但强制它不能在函数中创建(防止引用堆栈/删除对象)
我想出了下面的Error类型,并为此感到自豪,直到我意识到你可以在函数中做"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 : %dn", ErrConnect == ErrConnect);
printf("ErrConnect == ErrWrite : %dn", ErrConnect == ErrWrite);
printf("f() == ErrConnect : %dn", f() == ErrConnect);
printf("f() == ErrWrite : %dn", f() == ErrWrite);
printf("f() != ErrConnect : %dn", f() != ErrConnect);
printf("f() != ErrWrite : %dn", f() != ErrWrite);
printf("f() == Error::None : %dn", f() == Error::None);
printf("f() != Error::None : %dn", f() != Error::None);
printf("g() == Error::None : %dn", g() == Error::None);
printf("g() != Error::None : %dn", g() != Error::None);
printf("f().ToString() : %sn", f().ToString().c_str());
printf("ErrConnect.ToString() : %sn", ErrConnect.ToString().c_str());
auto err = f();
auto err2 = err;
auto err3 = err2;
printf("err3 == ErrConnect : %dn", err3 == ErrConnect);
auto err4 = h();
printf("err4 from h() : %sn", err4.ToString().c_str());
}
允许在全局范围内创建某些内容,而不是在函数中创建。
您所做的任何事情都不需要跟踪原始Error&
。相反,您希望创建一个错误来创建一个唯一的令牌,所有的Error
复制或从它移动,以携带这个令牌。该令牌不是必需的Error& this
,但是该令牌的生存期需要延长到从原始复制的所有Error
的生存期。
例如:
struct ErrorToken {
virtual std::string Description() const = 0;
~ErrorToken() {}
};
template<typename T>
struct ErrorTokenImpl:ErrorToken {
virtual std::string Description() const /* final override if C++11 */ {
return T::desc();
}
};
class Error {
ErrorToken* token;
template<typename T>
static ErrorToken* get_token() {
static std::unique_ptr<ErrorToken> retval( new ErrorTokenImpl<T>() );
return retval.get();
}
public:
template<typename T>
Error(): token( get_token<T>() );
bool operator==(Error const& o) const { return token == o.token; } // etc
std::string GetDescription() const {
return token->Description();
}
};
#define MAKE_ERROR(Y, X) Error< struct Y { static const char* desc() { return X; }; } >()
const Error ErrConnect = MAKE_ERROR(Connection, "failed to connect");
现在,任何人都可以在任何上下文中创建错误,但是每个错误的创建都有一个标记和一个字符串,并且创建的token
将持续到静态对象清理时间。
我发现实现这一点的最佳方法是使用静态std::atomic计数器(具体来说,_uint_fast64_t似乎最好),其中为error (const char *s)构造函数和std::atomic::fetch_add()中的每种错误类型创建id来获取/增加它:
http://en.cppreference.com/w/cpp/atomic/atomic唯一的缺点是这些只存在于c++ 11 (Visual Studio 2012;Linux应该不是问题(除了旧的发行版)。
我最终使用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");
相关文章:
- 智能指针作为无序映射键,并通过引用进行比较
- 将指针与引用进行比较
- 使用模板专用化来比较指针引用
- 类型ID指针和引用比较差异?
- 通过查看程序集来比较按值传递与按引用传递性能
- std::具有自定义比较函数结果的排序函数错误:必须调用对非静态成员函数的引用
- 比较地图对象及其引用C++
- 将 Java 的按值传递与C++的按值传递或引用进行比较
- 使用比较函数对引用类型失败
- 正确编写引用的比较运算符
- 在C++中,如何让(嵌套)比较函子引用封闭类的数据
- 比较未引用的映射迭代器(std::pairs):C2678
- 如何比较两个 std::istream 引用
- C++ std::sort 引用另一个列表的自定义比较函数
- 正在比较JNI对象引用
- C++ 无法将取消引用的字符指针与字符进行比较
- C++lambda通过引用捕获这个与捕获的比较
- 比较身份引用的标准方法
- 更好的std::在指针集合上查找,并将取消引用的值与常量引用值进行比较
- 通过引用比较链表中的节点