Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
xtorne21st
интересующийся
304 / 275 / 93
Регистрация: 25.09.2010
Сообщений: 1,056
1

Странное рекурсивное поведение объекта std::cout

09.02.2013, 17:34. Просмотров 952. Ответов 21
Метки нет (Все метки)

Пытался организовать очередь при помощи шаблона и наткнулся на "странное" поведение:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// Организация очереди при помощи шаблона
 
#include <iostream>
#include <cstdlib>
 
// По умолчанию тип int, размер 100
template <typename QType = int, int size = 100>
class Queue {
    QType a[size];
    int left, right;
 
    public:
    Queue();
    void qput(QType val);
    QType qget();
};
 
template <typename QType, int size>
Queue<QType, size>::Queue()
{
    left = right = 0;
}
 
template <typename QType, int size>
void Queue<QType, size>::qput(QType val)
{
    if (right == size) {
        std::cout << "Queue is full.\n";
        return; 
    }
    a[++right] = val;
}
 
template <typename QType, int size>
QType Queue<QType, size>::qget()
{
    if (left == right) {
        std::cout << "Queue is empty: ";
        return 0;
    }
    return a[++left];
}
 
int main()
{
    Queue<char> a;
 
    a.qput('e');
    a.qput('n');
    a.qput('g');
    a.qput('l');
    a.qput('i');
    a.qput('s');
    a.qput('h');
 
    std::cout << a.qget();
    std::cout << a.qget();
    std::cout << a.qget();
    std::cout << a.qget();
    std::cout << a.qget();
    std::cout << a.qget();
    std::cout << a.qget() << '\n';
 
    // Now queue is empty
    // another one
    a.qput('e');
    a.qput('n');
    a.qput('g');
    a.qput('l');
    a.qput('i');
    a.qput('s');
    a.qput('h');
 
    std::cout << a.qget() << a.qget() << a.qget() << a.qget()
        << a.qget() << a.qget() << a.qget() << '\n';
 
    return 0;
}
Bash
1
2
3
4
ilyuha21st@coldshoot:~/projects$ ./prog
english
hsilgne
ilyuha21st@coldshoot:~/projects$
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.02.2013, 17:34
Ответы с готовыми решениями:

Странное поведение cout после объявления объекта класса
List words; string strg; сin &gt;&gt; strg; сout &lt;&lt; strg; Ничего не выведет, пока...

Странное поведение std::string, полученного из std::stringstream
Есть код #include &lt;iostream&gt; #include &lt;sstream&gt; #include &lt;cstring&gt; int...

Операция std::cout для Объекта типа std::string
Кто детально объяснит почему не выводит ? Дает вот так &quot;Отсутствует оператор...

Странное поведение операции XOR и std::cin
Объясните, пожалуйста, почему этот код работает правильно: /* Обмен значений...

Объяснить поведение объекта std::cin в цикле while
#include&lt;iostream&gt; #include&lt;string&gt; #include&lt;cstdlib&gt; #include&lt;windows.h&gt;...

21
Kaimi
37 / 32 / 6
Регистрация: 17.09.2012
Сообщений: 66
09.02.2013, 18:30 2
C++
1
2
3
4
5
6
7
8
#include <iostream>
 
int main()
{
    int i = 0;
    std::cout << i * 2 << ++i;
    return 0;
}
И на экране видим 21.

Идея понятна?
1
Kastaneda
Jesus loves me
Эксперт С++
4943 / 3020 / 346
Регистрация: 12.12.2009
Сообщений: 7,622
Записей в блоге: 2
Завершенные тесты: 1
09.02.2013, 18:40 3
Цитата Сообщение от Kaimi Посмотреть сообщение
И на экране видим 21.
Идея понятна?
Тут дело в другом, действительно интересное поведение. Казалось бы, это тоже самое, что
C++
1
std::cout << 'e' <<  'n' ; // etc
но нет, компилятор генерит разный код.
Дизассемблировал в студии и в gcc, проблема не исчезла и суть получившегося кода одинакова (значит возможно это даже описано в стандарте, но лень туда лезть). Короче дело в следующем - в моем примере выше в стек кладется сначала 'n' потом 'e', т.е. внутри оператора << параметры будут извлекаться правильно, т.е. сначала 'e', потом 'n'. А вот этот код
C++
1
2
std::cout << a.qget() << a.qget() << a.qget() << a.qget()
        << a.qget() << a.qget() << a.qget() << '\n';
в ассемблере выглядет по-другому - аргументы кладутся в стек в порядке записи (т.е. 'e', 'n', 'g' и т.д.), значит внутри оператора << они будут извлечены в обратном порядке, что мы и видим на выходе.

На самом деле очень интересно, может кто-нибудь стандарт пошелестит?
0
Schizorb
510 / 462 / 82
Регистрация: 07.04.2012
Сообщений: 869
Записей в блоге: 1
Завершенные тесты: 1
09.02.2013, 19:09 4
Если не ошибаюсь, порядок вычисления операндов неопределен, кроме операций &&, || и ?:. То есть какой a.qget() будет выполнен первым, а какой последним - на усмотрение компилятора.
0
Jupiter
09.02.2013, 19:11
  #5

Не по теме:

Цитата Сообщение от Kastaneda Посмотреть сообщение
На самом деле очень интересно, может кто-нибудь стандарт пошелестит?
баян, можно и нагуглить, даже на этом форуме уже 100500 раз было

0
Croessmah
++Ͻ
14740 / 8422 / 1597
Регистрация: 27.09.2012
Сообщений: 20,714
Записей в блоге: 2
Завершенные тесты: 1
09.02.2013, 19:12 6
Цитата Сообщение от Schizorb Посмотреть сообщение
Если не ошибаюсь, порядок вычисления операндов неопределен, кроме операций &&, || и ?:.
Точки следования
1
Kastaneda
Jesus loves me
Эксперт С++
4943 / 3020 / 346
Регистрация: 12.12.2009
Сообщений: 7,622
Записей в блоге: 2
Завершенные тесты: 1
09.02.2013, 19:18 7
Цитата Сообщение от Jupiter Посмотреть сообщение
баян, можно и нагуглить, даже на этом форуме уже 100500 раз было
Так это UB или нет?

Не по теме:

Если честно, некогда гуглить, меня тут с компа гонят, сопротивлятся бесполезно:)



Тут дело даже не в порядке вычисления аргументов, т.к.
C++
1
2
std::cout << a.qget() << a.qget() << a.qget() << a.qget()
        << a.qget() << a.qget() << a.qget() << '\n';
тут же каждый << это отдельный вызов оператора, т.е. теоретически это эквивалентно
C++
1
2
3
4
5
6
7
    std::cout << a.qget();
    std::cout << a.qget();
    std::cout << a.qget();
    std::cout << a.qget();
    std::cout << a.qget();
    std::cout << a.qget();
    std::cout << a.qget() << '\n';
но практически мы видим обратное - сначала вызываются все a.qget(), а потом вызываются все operator<<().
0
Croessmah
++Ͻ
14740 / 8422 / 1597
Регистрация: 27.09.2012
Сообщений: 20,714
Записей в блоге: 2
Завершенные тесты: 1
09.02.2013, 19:21 8
Цитата Сообщение от Kastaneda Посмотреть сообщение
тут же каждый << это отдельный вызов оператора, т.е. теоретически это эквивалентно
Нет. В первом случае порядок вызова функций не определен и зависит от компилятора.
Во-втором, же у нас стоит ; которая ставит точку следования
1
OhMyGodSoLong
~ Эврика! ~
1246 / 995 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
09.02.2013, 19:22 9
Цитата Сообщение от Kastaneda Посмотреть сообщение
На самом деле очень интересно, может кто-нибудь стандарт пошелестит?
Enjoy your C++, что ещё сказать. Перегруженные операторы сохраняют приоритеты и ассоциативность соответствующих операторов, но при этом являются функциями со всеми вытекающими. Включая sequence point перед и после тела, но не между вычислениями операндов. Смотрите
C++
1
2
std::cout << 'e' <<  'n';
operator<<(operator<<(std::cout, 'e'), 'n');
и точно так же
C++
1
2
std::cout << a.qget() << a.qget() << a.qget();
operator<<(operator<<(operator<<(std::cout, a.qget()), a.qget()), a.qget());
Так вот, стандарт не обязывает вычислять аргументы в каком-то определённом порядке. Только чтоб они были вычислены до того, как пойдёт работа тела функции. Поэтому компилятор может как сначала вычислить внутренний operator<<(), а только потом вытянуть из очереди следующий элемент, так и наоборот — сначала вытянуть, запомнить его, и только потом приняться за operator<<(). Итого побочные эффекты типа "вывод в поток" оказываются упорядоченными правильно, а побочные эффекты "изменение состояния очереди" — в противоположном порядке. Так как вычисление значений обычных символов не имеет побочных эффектов, то с ними всё хорошо.

Справедливости ради, если б они оставались не функциями, а какими-то магическими "описателями операторов", то всё равно среди операторов sequence point есть только у запятой и тернарного.
1
Croessmah
09.02.2013, 19:40
  #10

Не по теме:

Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
sequence point есть только у запятой и тернарного.
у ленивых логических тоже есть

0
go
Эксперт С++
3637 / 1369 / 243
Регистрация: 16.04.2009
Сообщений: 4,527
09.02.2013, 19:56 11
Цитата Сообщение от Kastaneda Посмотреть сообщение
Так это UB или нет?
Анспецифик http://liveworkspace.org/code/ByMFa$0

Добавлено через 17 секунд
Цитата Сообщение от xtorne21st Посмотреть сообщение
на "странное" поведение:
Ничего странного здесь нет.
0
abit
272 / 271 / 83
Регистрация: 03.02.2013
Сообщений: 772
09.02.2013, 20:09 12
сдаётся мне из-за таких побочных эффектов в STL-ных stack и queue функции вытаскивания элементов разделены на две - одна вытаскивает, вторая уничтожает его в структуре

C++
1
2
3
4
5
6
7
8
9
#include <queue>
....
 
std::queue<char> a;
 
a.push('e'); - добавляет в очередь
 
std::cout << a.front(); - возвращает элемент, но не уничтожает его в очереди
a.pop(); - ничего не возвращает, но уничтожает элемент в очереди
0
Kastaneda
Jesus loves me
Эксперт С++
4943 / 3020 / 346
Регистрация: 12.12.2009
Сообщений: 7,622
Записей в блоге: 2
Завершенные тесты: 1
09.02.2013, 20:31 13
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
Так вот, стандарт не обязывает вычислять аргументы в каком-то определённом порядке. Только чтоб они были вычислены до того, как пойдёт работа тела функции.
Да, все дело в этом. Я ступил.

Не по теме:

Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
Enjoy your C++, что ещё сказать.
Ага, последнее время 50% рабочего времени пишу на assemler и 50% на С++ и то там С++ почти С. Короче забывать стал, до устройства на работу (1.5 г. назад) я С++ знал куда лучше, чем сейчас:)


go, не понял, зачем ссылка на LWS? Там тоже самое.

Добавлено через 4 минуты
Цитата Сообщение от abit Посмотреть сообщение
сдаётся мне из-за таких побочных эффектов в STL-ных stack и queue функции вытаскивания элементов разделены на две - одна вытаскивает, вторая уничтожает его в структуре
нет
0
xtorne21st
интересующийся
304 / 275 / 93
Регистрация: 25.09.2010
Сообщений: 1,056
09.02.2013, 20:39  [ТС] 14
Цитата Сообщение от go Посмотреть сообщение
Ничего странного здесь нет.
ну для кого как). если не знатешь в чём дело (а я не знал вём дело), мне этот момент показался странным.
0
go
Эксперт С++
3637 / 1369 / 243
Регистрация: 16.04.2009
Сообщений: 4,527
09.02.2013, 21:01 15
Цитата Сообщение от Kastaneda Посмотреть сообщение
go, не понял, зачем ссылка на LWS? Там тоже самое.
http://liveworkspace.org/code/2jD21P$0

Цитата Сообщение от xtorne21st Посмотреть сообщение
мне этот момент показался странным.
Так с стандарте все есть
1
xtorne21st
интересующийся
304 / 275 / 93
Регистрация: 25.09.2010
Сообщений: 1,056
09.02.2013, 21:30  [ТС] 16
Цитата Сообщение от go Посмотреть сообщение
Так с стандарте все есть
Я бы с радостью начал изучать стандарт, но на данном этапе нахожу более полезным почитать какого-нибудь автора. А уж потом, когда большинство аспектов и приёмов дойдут до автоматизма, и обычное чтении книг уже не будет вызывать кокой-либо интерес, тогда уже можно будет начать изучать стандарт. Имхо.
0
Kastaneda
Jesus loves me
Эксперт С++
4943 / 3020 / 346
Регистрация: 12.12.2009
Сообщений: 7,622
Записей в блоге: 2
Завершенные тесты: 1
09.02.2013, 21:52 17
Цитата Сообщение от go Посмотреть сообщение
http://liveworkspace.org/code/2jD21P$0
go, а теперь для тех, кто сегодня тупит - в чем разница? Всмысле я вижу, что вывод отличается от предыдущего, но разницы в коде беглым взглядом не вижу.

Добавлено через 6 минут
Аааа, вижу снимаю вопрос.
0
xtorne21st
интересующийся
304 / 275 / 93
Регистрация: 25.09.2010
Сообщений: 1,056
09.02.2013, 22:31  [ТС] 18
Цитата Сообщение от Kastaneda Посмотреть сообщение
Аааа, вижу снимаю вопрос.
Так поделитесь пожалуйста с другими что вы там заметили, я лично скомпилировал этот код у себя на машине и результат как и прежде.
0
go
Эксперт С++
3637 / 1369 / 243
Регистрация: 16.04.2009
Сообщений: 4,527
09.02.2013, 22:32 19
Цитата Сообщение от Kastaneda Посмотреть сообщение
но разницы в коде беглым взглядом не вижу.
xtorne21st, А ее там нет. Код я скопировал полностью, только компилятор clang поставил.


xtorne21st, из стандарта С++
Цитата Сообщение от C++
The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is unspecified.
Иными словами все зависит от компилятора.
0
xtorne21st
интересующийся
304 / 275 / 93
Регистрация: 25.09.2010
Сообщений: 1,056
09.02.2013, 22:36  [ТС] 20
единственное в чём разница, так это в компиляторе, clang и gcc с одними и теме же ключами генерирует разный код...

Добавлено через 2 минуты
Цитата Сообщение от go Посмотреть сообщение
The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is unspecified.
Это вы с N3242 взяли? Можете указать страничку, пожалуйста

Добавлено через 37 секунд
Цитата Сообщение от go Посмотреть сообщение
Иными словами все зависит от компилятора.
Немножко меня опередили)
0
09.02.2013, 22:36
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.02.2013, 22:36

Не воспринимает ни std::cout, ни std::cin. Вобщем ничего из std. Также не понимает iostream
Здравствуйте! Я хотел начать изучать язык C++. Набрал литературы. Установил...

Cout like: перегрузить оператор<< по примеру объекта cout для extern объекта пользовательского типа
Мне нужен extern объект по примеру cout с перегруженным оператором. Я нечто...

В чем разница std::cout и просто cout?
Ребят ,подскажите на простом языке для чайников . В чем разница std::cout и...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru