在 C++ 中将 int 作为 bool 参数传递

Passing int as bool argument in C++

有人可以解释这段代码中发生了什么吗:

示例: https://ideone.com/1cFb4N

#include <iostream>

using namespace std;

class toto
{
public:
    bool b;
    toto(bool x)
    {
        cout<< "constructor bool:" << (x ? "true": "false")<<endl;
        b = x;
    }
    ~toto() {}
};

int main()
{
    toto t = new toto(0);
    cout << "t.b is " << (t.b ? "true": "false")<<endl;
    t = new toto(false);
    cout << "t.b is " << (t.b ? "true": "false")<<endl;
    return 0;
}

输出:

constructor bool:false
constructor bool:true
t.b is true
constructor bool:false
constructor bool:true
t.b is true

在此声明中

toto t = new toto(0);

class 类型 toto 的对象 t 由表达式 new toto(0) 返回的指针初始化。由于返回的指针不等于 nullptr 然后它被隐式转换为布尔值 true.

所以事实上你有

toto t = true;

除了内存泄漏,因为分配对象的地址丢失了。所以分配的对象不能删除。

你可以想象上面的声明是这样的。

toto *ptr = new toto(0)
toto t = ptr;

所以这个输出的第一行

constructor bool:false
constructor bool:true

对应参数为0的动态创建对象

new toto(0)

然后将返回的指针用作初始化器,并隐式转换为布尔值true,用于初始化声明的对象t。所以第二行显示调用了值为true的转换构造函数(带参数的构造函数)。

上面的声明和这个赋值语句没有太大区别

t = new toto(false);

因为在赋值的右边再次使用了一个指针。

所以隐式定义的复制赋值运算符将不等于nullptr的指针的值转换为布尔值true.

这个作业你可以想象成下面的样子

toto *ptr = new toto(false);
t = toto( ptr );

再次发生内存泄漏。

来自 C++ 14 标准(4.12 布尔转换)

1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true. For direct-initialization (8.5), a prvalue of type std::nullptr_t can be converted to a prvalue of type bool; the resulting value is false.

在此声明中:

toto t = new toto(0);

在表达式 new toto(0) 中,您正在分配具有默认参数 0toto。此 int 可以隐式转换为 boolfalse,并调用 bool 构造函数,结果输出:

constructor bool:false

那么你在做作业:

toto t = /* pointer returned by new */;

此指针可以隐式转换为 bool,并且由于此指针不是 nullptr,因此它具有 non-zero 值。这与接受 booltoto 构造函数不是 explicit 的事实相结合意味着 bool 的构造函数被调用用于 t,导致:

constructor bool:true

这使得 tb 成员具有值 true,因此下一行代码导致输出:

t.b is true

任何整数值都可以隐式转换为 bool,其中 0 转换为 false,所有其他值转换为 true

同样适用于指针,空指针转换为false,所有其他转换为true

toto t = new toto(0); 等同于:

// Create new toto instance, convert 0 to false and assign to p
toto* p = new toto(0);
// Create toto instance on the stack and convert non-null pointer p to true
toto t = toto(p);

您可以通过将单参数构造函数标记为 explicit 来防止这些令人惊讶的转换,这意味着在隐式转换期间不允许考虑它们:

class toto
{
public:
    bool b;
    explicit toto(bool x)
    {
        cout<< "constructor bool:" << (x ? "true": "false")<<endl;
        b = x;
    }
    ~toto() {}
};