Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Глюк с выводом связного списка


Автор: nikitao 1.10.2005, 21:16
Добрый <время суток>Вот программа:

Код

#include <iostream>
using namespace std;
template <class X> class ochered{
  ochered *next;
  ochered *head;
  ochered *tail;
  X i;
  public:
    ochered(){head=tail=next=NULL;}
    void add(X a){
    ochered *temp;
    temp=new ochered;
    if (!temp)
    {
      cerr<<"Oshibka vidilenia pamati";
      exit(1);
    }
    temp->next=NULL;
    temp->i=a;
    if (!head){
      head=temp;
      tail=head;}
    else
    {
      tail->next=temp;
      tail=temp;
    }
    }
    X vivod()
    {
      X temp;
      temp=head->i;
      head=head->next;
      return temp;
    }
};
int main()
{
  ochered<int> ob1;
  ob1.add(30);
  ob1.add(239);
  ob1.add(566);
  cout<<ob1.vivod()<<'  '<<ob1.vivod()<<'  '<<ob1.vivod()<<'\n';
  system("PAUSE");
  return 0;
}


Здесь реализуется связный список с помощью создания шаблона(это не суть дела).
Лично я перед компиляцией ожидал увидеть в окне такую строку
"30 239 566"
но увидел:
"566 239 30"
Почему так произходит до меня не доходит.
Если прописать вместо
Код

cout<<ob1.vivod()<<'  '<<ob1.vivod()<<'  '<<ob1.vivod()<<'\n';

строку
Код

cout<<ob1.vivod();

или
Код

cout<<ob1.vivod();
  cout<<ob1.vivod();
  cout<<ob1.vivod();

То все работает нормально.Пыталя посмотреть в отладки:поставил точку останова и посмотрел выдаваемое значание в ochered::vivod();.Все выдает нормально ,а в окне глюк такой.
Зарание спасибо. smile

Автор: LPBOY 1.10.2005, 21:55
Инструкция:
Код

cout<<ob1.vivod()<<'  '<<ob1.vivod()<<'  '<<ob1.vivod()<<'\n';


трансформируется в:

Код

std::operator<<(operator<<(operator<<(cout, ob1.vivod()), ob1.vivod()), ob1.vivod());


если нигде не опечатался. Но суть в том что компилятору разрешается производить вычисления своих аргументов в любом порядке - т.н. неспецифицированное поведение. Кроме того здесь судя по всему вступает в действие правило о разделении модификаций объекта точками следования. У тебя получается аж три модификации объекта и ни одной точки следования между ними. - Это приводит к неопределенному поведению, например MSVC 7.1 выдает полный бред.
Добавлено @ 22:01
А вообще что ты реализуешь? Очередь или двусвязный список? И какой компилятор?
Ты после выделения памяти проверяешь на ноль. Вообще-то компилятор должен бросать исключение, хотя старые действительно возвращают ноль...

Автор: nikitao 1.10.2005, 22:28
Цитата
А вообще что ты реализуешь? Очередь или двусвязный список? И какой компилятор?
Ты после выделения памяти проверяешь на ноль.

Реализую я очередь,но это не важно.IDE C++BuilderX v 1.0 а компелятор Borland Win32.
Вобще ,как я понял надо быть осторожнее с выводом.
Цитата

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

Пока еще не научился обрабатывать исключения,поэтому по старинке проверяю(вроде все работает).

LPBOY,спасибо.
ЗЫ А что такое точка следования???

Автор: bilbobagginz 1.10.2005, 22:37
выкури man fflush
пока.

Автор: LPBOY 1.10.2005, 23:04
В общем правило такое: если несколько раз модифицируешь одну и ту же переменную (в твоем примере функция vivod каждый раз модифицирует ob1), то модификации должны отделяться точками следования. Точки следования это:
- точка с запятой
- оператор запятая
- оператор ?:
- операторы && и ||
- а также перед началом выполнения некоторой функции и в самом конце ее выполнения

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

Код

cout<<ob1.vivod();
cout<<ob1.vivod();
cout<<ob1.vivod();

Автор: LPBOY 1.10.2005, 23:43
Это я тебе рассказал - почему у меня выдается мусор (неопределенное поведение) ;)
Теперь расскажу - почему у тебя они выходят в обратном порядке (не специфицированное поведение). Я тут поэкспериментировал, написал такой код:

Код

#include <iostream>

int func()
{
static int val;
++val;
return val;
}

int main()
{
    std::cout << func() << ' ' << func() << ' ' << func(); 
    return 0;
}


он выдал:

Цитата

3 2 1


Как видишь компилятор вычисляет параметры функции operator<< так как ему нравится. То что именно справа налево видимо связано с конвенцией __cdecl.

Автор: nikitao 2.10.2005, 00:44
Угу,понятно,разьяснил. smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)