C++中bool类型的默认值是什么?

14

我正在重新设计一个C++类的构造函数,需要捕获未指定的bool值。我已经为所有其他参数使用了默认值,但据我了解,bool类型只能被初始化为true或false。由于这两种情况在类中都有意义,那么我应该如何处理检查默认值是否更改的情况呢?


7
是否重要知道你是否使用了初始化为“false”的默认值“false”? - RobS
13个回答

40

现实情况是你无法做到这一点。bool类型具有值,即true或false,如果你没有初始化它,那么它将随机地变成true或false,可能在程序的每次运行或类的分配时都不同。

如果你需要一个具有更多选项的类型,请定义一个枚举。

typedef enum MyBool {
    TRUE,
    FALSE,
    FILENOTFOUND
} MyBool;

16
从thedailywtf.com偷来的? :) - JaredPar
4
适用于 DailyWTF 参考的有趣内容。 - Greg Hewgill
我喜欢这个答案,但我想稍微调整一下,加入一个DEFAULT而不是FILENOTFOUND,所以我发布了另一个版本的答案。 - Azder
1
StackOverflow没有这个完全相关的答案就不完整了;我感谢你。 - aib
75
很好的细节,将TRUE == false和FALSE == true放在一起。 - Motti
6
如果您不对布尔值进行初始化,它甚至可能既不是真也不是假,这非常危险(未定义)。 - Johannes Schaub - litb

38

三态布尔是通往黑暗面的道路。三态布尔会导致愤怒。愤怒导致仇恨。仇恨导致痛苦。


最好不要使用三态布尔。

相反,使用一个额外的布尔值来确定第一个布尔值是否已经“初始化”(或更好地说是“已知”)。

class Prisoner : public Person
{


  ...

  bool is_veredict_known;
  bool is_guilty;
}

如果还不知道判决结果,你无法确定被告是否真的有罪,但你的代码可以区分不同的情况。当然,宪法保证is_guilty的默认值应该是false,但是...... :)

顺便说一下,类不变式应该包括:

assert(is_veredict_known || !is_guilty);

18

6
你甚至可以为你的 DailyWTF 需求设置 boost::tribool:BOOST_TRIBOOL_THIRD_STATE(FILENOTFOUND)。 - Michael Burr

5
如果您需要这样的话,创建一个代表可能未初始化的值的概念的值。
template <typename T>
struct Maybe {
  Maybe() : m_hasValue(false) {}
  bool HasValue() const { return m_hasValue; }
  T& Value() { ThrowIfFalse(m_hasValue); return m_value; }
  const T& Value() const { ThrowIfFalse(m_hasValue); return m_value; }
  void SetValue( _In_ const T& value) { m_value = value; m_hasValue = true; }
private:
  bool m_hasValue;
  T m_value;
};

现在,您可以表示您所需的所有三种状态。
class SomeType { 
  ...
  Maybe<bool> m_myBool;
}

2
+1:如果C++有闭包会更好。我猜你可以用函数指针模拟它们。(附注:不喜欢类名)。 - graham.reeds

4
在C++中,bool只有一位信息,要么是0,要么是1。由于您想表示三种可能的状态,因此需要更多的信息位。有两种常见的技术:
  1. 使用另一个bool值来指示该值是否为“默认值”,或者
  2. 使用具有三个值(默认值、true、false)的枚举类型来指示。
我可能会选择选项1。

3

使用优秀的boost::optional。不仅适用于布尔值,而且适用于您在其他地方使用了一些未初始化的脏数值。其使用方式如下:

void function(optional<int> value) {
   if (value)
      std::cout << "value is defined: " << value.get() << "\n";
   else
      std::cout << "value is not defined\n";
}

以下是一个返回可选项的函数示例:

struct MapClass {
   map<string,int> m_map;

   optional<int> getValue(string key) {
      optional<int> result = none;
      if (m_map.find(key) != m_map.end())
         result = m_map[key];
      return result;
   }
}

3
struct Bool { //guaranteed initialized bool
    bool v;

    Bool() : v(false) {}
    operator bool() const { return v; }
    bool& operator=(const bool val){ return v = val; }
};

2

你可以拥有一个单独的私有成员来表示布尔值是否已经被初始化。


1

你真的不能这样做。你可以提供第二个构造函数,例如:

class MyClass {
  public:
    MyClass(bool bFlag); // <-- not default
    MyClass(void);       // <-- default
};

这与我被告知要清理的现有内容类似 :) - voteblake
你真的需要暴露默认构造函数吗? - wreckgar23
我不能代表原帖作者发言,但一般来说,你不需要这样做。 - Marc Bernier

1

我不太明白,但我会尝试...

当您有一个聚合初始化程序留下一些值未指定时,将应用默认值。在这种情况下,bool的默认值将为false。在类中,“默认”值将未初始化,这意味着它可以是任何值,并且可以从运行到运行更改。

如果您对bool是否已更改感兴趣,则最好使用第二个bool跟踪它,默认为false,或使用表示3种可能状态的枚举。如果您真正想要3种状态,那么您真的不需要一个bool。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接