感谢您的所有 cmets/answers/contributions。在这里,我将网上找到的不同想法和其他想法融合在一起(我阅读了很多文档和源代码)。
检查值是否存在
最合乎逻辑的方式。源代码(库和应用程序)都是初学者可以理解的。这适合KISS principle。此外,这可以移植到其他编程语言,如 Java...
Library: | Application:
|
struct iterator |
{ |
bool isSet() const | if (it.isSet())
{ | {
return p; | int v = it.get();
} | //get() may also call isSet()
|
int get() const | //continue processing
{ | }
return *p; | else //value is not set
} | {
| //do something else
int* p; | }
}; |
如果函数get() 不检查isSet() 并且(应用程序的)开发人员忘记调用isSet()(在get() 之前),则应用程序代码可能会崩溃(分段错误)。
另一方面,如果get() 函数调用isSet(),则isSet() 处理会执行两次。然而,最近的编译器应该避免这种第二次不必要的isSet() 处理。
2。返回我的一位同事建议的标志值或默认值
Library: | Application:
|
struct iterator | int i = it.get()
{ | if (i >= 0)
int get() const | {
{ | unsigned short v = i;
if(p) return *p; |
else return -1; | //continue processing
} | }
| else //value is not set
unsigned short* p; | {
}; | //do something else
| }
有些人认为异常不利于二进制代码优化。但是,如果 throw exception 是内联的,最好的编译器可能会优化二进制代码,并且比
此外,此解决方案可能允许最佳优化的二进制代码,因为isSet() 被调用了两次。但这取决于编译器的优化能力。
图书馆:
struct iterator
{
bool get() const
{
if (isSet()) return *p;
else throw;
}
private:
bool isSet() const { return ....; }
....
};
应用:
int value;
try
{
value = it.get();
}
catch (...)
{
value = 0; // default value
}
4。使用operator explicit_cast<bool> () const
请参考写得好的Luis's answer。
5。用operator写优雅的if(it)
使用explicit conversion operators introduced in C++11可以很好地实现这个解决方案。
图书馆:
struct iterator
{
explicit operator bool() const { return ....; }
....
};
应用:
int value;
if (it) //very elegant C++ fashion
{
value = it.get();
}
else
{
value = 0; // default value
}
但是,我们仍处于 2012 年,当前的源代码必须与不支持显式转换运算符的编译器兼容。在这些编译器上,年复一年地实现了不同的可能性。我将在下一章介绍所有这些内容。
在 C++11 之前启用语句if(it)
本章的源代码灵感来自Bjarne Stroustrup在2004年写的书More C++ idioms,更具体地说是@PlasmaHH指出的The Safe Bool Idiom部分。
1。隐式operator bool
当explicit不可用时,我们可以只使用隐式转换运算符。
图书馆:
struct iterator
{
operator bool() const { return ....; } //implicit conversion
....
};
应用:
int value;
if (it) //this works very well!
{
value = it.get();
}
else
{
value = 0; // default value
}
// But these other instructions are also correct :(
int integer = it; //convert it to bool, then convert bool to int
if (-6.7 < it) //.................., then convert bool to double, and compare
it << 1;
2。 operator!
这是boost::thread (v1.51) 中使用的解决方案,作为explicit operator bool() 的解决方法,用于unique_lock、shared_lock、upgrade_lock 和upgrade_to_unique_lock。
图书馆:
struct iterator
{
bool operator!() const { return ....; }
....
};
应用:
int value;
if (!!it) // !! looks strange for many developers
{
value = it.get();
}
else
{
value = 0; // default value
}
if (it) //ERROR: could not convert ‘it’ from ‘iterator’ to ‘bool’
{
value = it.get();
}
3。 operator void*
这是 STL 流使用的解决方案。例如参考文件bits/basic_ios.h (std::basic_ios)。
图书馆:
struct iterator
{
operator void*() const { return ....; }
....
};
应用:
int value;
if (it) //this works very well!
{
value = it.get();
}
else
{
value = 0; // default value
}
// But these other instructions are also correct :(
delete it; //just a warning: deleting 'void*' is undefined
if (it > std::cin) //both are converted to void*
void* r = it;
4。隐式转换为未定义的嵌套 class
这个解决方案是Don Box在1996年提出的。
图书馆:
struct iterator
{
private:
class nested; //just a forward declaration (no definition)
int* v_;
public:
operator nested*() const { return v_ ? (nested*)this : 0; }
};
应用:
int value;
if (it) //this works very well!
{
value = it.get();
}
else
{
value = 0; // default value
}
// But these other instructions are also correct :(
iterator it2;
if (it < it2)
int i = (it == it2);
5。 @CashCow 提出的安全bool 成语
Bjarne Stroustrup 提出了utimate solution 没有缺点。以下是简化版。
图书馆:
struct iterator
{
private:
typedef bool (iterator::*bool_type)() const;
bool private_() const {}
int* v_;
public:
operator bool_type() const { return v_ ? &iterator::private_ : 0; }
};
//forbids it1 == it2
template <typename T>
bool operator == (const iterator& it,const T& t) { return it.private_(); }
//forbids it1 != it2
template <typename T>
bool operator != (const iterator& it,const T& t) { return ! (it == t); }
应用:
int value;
if (it) //this works very well!
{
value = it.get();
}
else
{
value = 0; // default value
}
// All other instructions fail to compile
iterator it2;
if (it > it2) ; //ERROR: no match for ‘operator>’ in ‘it > it2’
if (it == it2) ; //ERROR: ‘bool iterator::private_() const’ is private
if (it != it2) ; //same error
6。可重复使用的保险箱bool 成语
这个比较复杂,源码请参考Wikibooks。
图书馆:
struct iterator : safe_bool <iterator> //I do not want virtual functions
{
bool boolean_test() const { return ....; }
....
};
最近的 STL 和 boost 提供设施。一些例子:
- GNU STL --> 查看文件 tr1/functional 和 exception_ptr.h
- 每个 Boost 组件都使用自己的
safe_bool:
- Spirit --> 查看文件 spirit/include/classic_safe_bool.hpp 和 spirit/home/classic/core/safe_bool.hpp
- IOstream --> 查看文件 iostreams/device/mapped_file.hpp
- 参数 --> 参数/aux_/maybe.hpp
- 可选
- 功能
- 范围
- 逻辑(tribool)
但是 Matthew Wilson 在他的书 Imperfect C++ 中说,safe_bool 可能会导致对未实现 Empty Base Optimization 的编译器的大小惩罚。尽管大多数现代编译器在单继承方面都会这样做,但多继承可能会造成大小损失。