Может кто-нибудь объяснить, что происходит в этом коде:

здесь: 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
42
Serge 8 Окт 2020 в 00:38

3 ответа

Лучший ответ

В этой декларации

toto t = new toto(0);

Объект t типа класса toto инициализируется указателем, возвращаемым выражением 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 Значение арифметики, перечисление без области действия, указатель или указатель в тип члена может быть преобразован в значение типа bool. ноль значение, значение нулевого указателя или значение указателя нулевого члена преобразуется к ложному; любое другое значение преобразуется в истину. Для прямая инициализация (8.5), prvalue типа std :: nullptr_t может быть преобразовано в prvalue типа bool; результирующее значение ложно.

78
Vlad from Moscow 8 Окт 2020 в 13:04

В этом заявлении:

toto t = new toto(0);

В выражении new toto(0) вы выделяете toto с аргументом по умолчанию 0. Этот int может быть неявно преобразован в значение bool false, и это вызывает конструктор bool, что приводит к выводу:

constructor bool:false

Затем вы выполняете задание:

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

Этот указатель может быть неявно преобразован в bool, и поскольку этот указатель не является nullptr, он имеет ненулевое значение. Это в сочетании с тем фактом, что конструктор toto, принимающий bool не является explicit, означает, что конструктор из bool вызывается для t, в результате чего:

constructor bool:true

И это заставляет член b в t иметь значение true, и, следовательно, следующая строка кода дает результат:

t.b is true
19
cigien 7 Окт 2020 в 21:51

Любое целочисленное значение неявно преобразуется в 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() {}
};
20
Remy Lebeau 7 Окт 2020 в 21:56