Создать целочисленный класс C ++, чтобы он действовал абсолютно идентично целочисленному целочисленному типу - PullRequest
6 голосов
/ 27 октября 2011

Маленькая и довольно неприятная проблема, которую я видел несколько дней назад, спросил у моего друга на собеседовании.

Первоначальный вопрос интервью был: «Каким будет вывод следующего кода?»

int i = 2;
i = i++ + i++;

Правильный ответ ((2 + 2) + 1) + 1 = 6, т. Е. Постинкремент применяется дважды до назначения, но после добавления.

Затем я хотел создать простой класс, содержащий одно целое число и оператор перегрузки + () и оператор ++ (int), чтобы видеть в журналах точный порядок, в котором будут выполняться операторы.

Вот что я получил:

class A
{
public:
A(int _data) : data(_data) { }

A &operator=(const A& _rhs)
{
    data = _rhs.data;
    cout<<" -- assign: "<<data<<endl;
}

A operator++(int _unused)
{
    A _tmp = data;
    data++;

    cout<<" -- post-increment: "<<data<<endl;
    return _tmp;
}

A operator+(const A &_rhs)
{
    A _tmp = data + _rhs.data;

    cout<<" -- addition: "<<data<<"+"<<_rhs.data<<endl;
    return _tmp;
}

inline operator int() const { return data; }

private:
    int data;
};

Результат был довольно обескураживающим:

-- post-increment: 3
-- post-increment: 4
-- addition: 3+2
-- assign: 5

Для менее сложных конструкций, таких как (A _dt2 = a ++;), он действует как следует, но порядок выполнения операторов не такой, как для целочисленных типов.

Это может быть специфическая проблема компилятора, я думаю:

$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Итак, я немного растерялся:)

Ответы [ 4 ]

14 голосов
/ 27 октября 2011

Первоначальный вопрос интервью был: «Каким будет вывод следующего кода?»

int i = 2;
i = i++ + i++;

Правильный ответ: неопределенное поведение , потому что вы изменяете одну и ту же переменную несколько раз без точки последовательности между ними.

C ++ 03 Standard §5 [expr] p4:

За исключением отмеченных случаев, порядок вычисления операндов отдельных операторов и подвыражений отдельных выражений и порядок возникновения побочных эффектов не уточняются.

Это может не отвечать на ваш реальный вопрос, но будет аналогичным, даже если вы создадите целочисленный класс и перегружаете operator++(int) и operator+(A const&). Порядок вычисления аргументов функции не определен, это может быть сделано в любом порядке, который нравится компилятору, поэтому результат не определен.

7 голосов
/ 27 октября 2011

Помимо того, что уже отмечали другие: взяв название вашего вопроса в отдельности - «Создайте целочисленный класс C ++, чтобы он действовал абсолютно идентично целочисленному целочисленному типу» - я должен указать на совершенно другую причину, по которой это невозможно .

(насколько мне известно) невозможно эмулировать поведение ярлыков операторов || и && с классами, то есть с обеих сторон операнд будет оцениваться независимо от того, что.

Редактировать: Ознакомьтесь с комментариями. «Насколько мне известно», кажется, было недостаточно. Однако у Стива Джессопа есть другой пример, который подтверждает правильность общей точки.

Это совершенно не связано с вашим вопросом приращения, но актуально для заголовка вашего вопроса, поэтому я подумал, что его следует упомянуть.

4 голосов
/ 27 октября 2011

Правильный ответ ((2 + 2) + 1) + 1 = 6, т. Е. Постинкремент применяется дважды до назначения, но после добавления.

Это не правильный ответ:

За исключением отмеченных случаев, порядок вычисления операндов отдельных операторов и подвыражений отдельных выражений, а также порядок возникновения побочных эффектов не определены. Между предыдущей и следующей точкой последовательности скалярному объекту должно быть изменено его сохраненное значение не более одного раза путем оценки выражения. Кроме того, предварительное значение должно быть доступно только для определения значения, которое будет сохранено. Требования этого параграфа должны выполняться для каждого допустимого порядка подвыражений полного выражение; в противном случае поведение не определено.
- ISO-IEC-14882

1 голос
/ 27 октября 2011

На самом деле, вы допустили довольно серьезную ошибку на раннем этапе.

Первоначальный вопрос интервью был: «Каким будет вывод следующего кода?»

int i = 2;
i = i++ + i++;

Правильный ответ на этот вопрос: «Результат не определен».

Изменяя и читая переменную без промежуточной точки последовательности, вы вызываете неопределенное поведение.


Более конкретно, в этом случае вас в заднице кусает то, что порядок, в котором оцениваются параметры для оператора +, не определен; и это справедливо в общем случае как для операторов, так и для функций, за некоторыми заметными исключениями, а именно для короткозамкнутых логических операторов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...