感谢您的所有评论/答案/贡献。在这里,我将网上找到的不同想法和其他想法融合在一起(我阅读了很多文档和源代码)。
检查价值存在
最合乎逻辑的方式。源代码(库和应用程序)都是初学者可以理解的。而这符合KISS原则。此外,这可以移植到其他编程语言,如 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
请参阅写得很好的路易斯的回答。
5.用operator
写优雅if(it)
使用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 年,当前的源代码必须与编译器兼容,而不支持显式转换运算符。在这些编译器上,年复一年地实现了不同的可能性。我将在下一章介绍所有这些内容。
if(it)
在 C++11 之前启用语句
本章的源代码灵感来自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) 中使用的解决方案,作为for 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);
Bjarne Stroustrup提出了没有缺点的最佳解决方案。下面是简化版。
图书馆:
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
- 选修的
- 功能
- 范围
- 逻辑(三元组)
但是 Matthew Wilson 在他的《不完美的 C++ 》一书中说,这safe_bool
可能会导致对未实现Empty Base Optimization的编译器的大小惩罚。尽管大多数现代编译器在单继承方面都会这样做,但多继承可能会造成大小损失。