Debag Vs Release

Тема в разделе "C и С++ FAQ", создана пользователем Vadik(R), 7 мар 2014.

  1. Vadik(R)

    Vadik(R) Well-Known Member

    Регистрация:
    12 дек 2007
    Сообщения:
    483
    Симпатии:
    0
    Добрый вечер-ночи, уважаемые форумчане.
    Недавно наткнулся на такую интересную вещь, которую никак объяснить не могу. Вот код:
    Код (C++):
    #include <iostream>
    #include <locale>

    using namespace std;

    int max(int a, int b)
    {
    return a > b ? a : b;
    }

    class Polynom
    {
    public:
    Polynom()
    {
    n = 1;
    k = (int*) malloc(n * sizeof(int));
    k[0] = 0;
    }

    Polynom(int n, int k[])
    {
    this->n = n;
    this->k = (int*) malloc(this->n * sizeof(int));
    memcpy(this->k, k, this->n * sizeof(int));
    }

    Polynom& operator=(Polynom &other)
    {
    cout << "Start operator=" << endl;
    this->n = other.n;
    this->k = (int*) malloc(this->n * sizeof(int));
    memcpy(this->k, other.k, this->n * sizeof(int));
    cout << "End operator=" << endl;
    return *this;
    }

    ~Polynom()
    {
    cout << "Start free k" << endl;
    free(k);
    cout << "End free k" << endl;
    }

    int rank()
    {
    return n;
    }

    int operator[] (int index)
    {
    return k[index];
    }

    Polynom sum(Polynom &a, Polynom &b)
    {
    int i;
    int* k;
    int n;
    Polynom c;
    n = max(a.rank(), b.rank());
    k = (int*) malloc(n * sizeof(int));
    for (i = 0; i < n; i++)
    {
    k[i] = 0;
    if (i < a.rank())
    {
    k[i] += a[i];
    }
    if (i < b.rank())
    {
    k[i] += b[i];
    }
    }
    c = Polynom(n, k);
    free(k);
    return c;
    }

    void Print()
    {
    int i;
    for (i = 0; i < n; i++)
    {
    if (i)
    {
    printf("+ ");
    }
    printf("%d * a ^ %d ", k[n - i - 1], n - i - 1);
    }
    printf("\r\n");
    }

    private:
    int* k;
    int n;
    };

    int main()
    {
    int k[10];
    Polynom a;
    Polynom b;
    k[0] = 1;
    k[1] = -2;
    k[2] = 1;
    a = Polynom(3, k);
    k[0] = -1;
    k[1] = 1;
    b = Polynom(2, k);
    a = a.sum(a, b);
    a.Print();
    return 0;
    }
    Тут реализуется класс многочлен, где задаётся его степень и сами коэффициенты. Делается динамическим выделением памяти.
    Для примера создал два многочлена:
    1: x^2 - 2x + 1
    2: x - 1
    И решил их сложить.
    Так вот, проблема вся в том, что если программа в режиме Release, то он их отлично складывает и выводит результат на экран.
    А вот если она в Debug, то выдаётся ошибка:
    На_форум.png
    Как такое происходит? Как этого избежать? Можно в деструкторе закомментировать //free(k); , тогда ошибка выдаваться не будет, но будет утечка памяти. Прошу совета, как быть в такой ситуации, что в коде не так? С помощью cout'ов я понял, что ошибка выдаётся именно в деструкторе, но больше ничего понять не могу.
     
  2. rrrFer

    rrrFer Well-Known Member
    Команда форума C\C++ Team

    Регистрация:
    6 сен 2011
    Сообщения:
    1.324
    Симпатии:
    36
    Я вообще не понимаю как этот код может работать.
    Это: c = Polynom(n, k);
    как так ?

    А еще это:
    a = Polynom(3, k);
    это:
    b = Polynom(2, k);
    и вот это:
    a = a.sum(a, ;);

    Ты не понимаешь, что тут:
    Polynom a;
    Polynom b;

    ты уже создал 2 объекта. А тут: Polynom(2, k); ты создал еще один объект.
    Нельзя просто так взять и присвоить.

    Что делает sum мне вообще не понятно. Если она не статическая, то нахрена она принимает 2 аргумента. Если принимает 2 аргумента - то зачем ей this? - почему не статическая?

    Код (Text):
    #include <iostream>
    #include <locale>
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>

    using namespace std;

    int max(int a, int b)
    {
    return a > b ? a : b;
    }

    class Polynom
    {
    public:
    Polynom()
    {
    n = 1;
    k = (int*) malloc(n * sizeof(int));
    k[0] = 0;
    }

    Polynom(int n, int k[])
    {
    this->n = n;
    this->k = (int*) malloc(this->n * sizeof(int));
    memcpy(this->k, k, this->n * sizeof(int));
    }

    Polynom& operator=(Polynom &other)
    {
    cout << "Start operator=" << endl;
    this->n = other.n;
    this->k = (int*) malloc(this->n * sizeof(int));
    memcpy(this->k, other.k, this->n * sizeof(int));
    cout << "End operator=" << endl;
    return *this;
    }

    ~Polynom()
    {
    cout << "Start free k" << endl;
    free(k);
    cout << "End free k" << endl;
    }

    int rank()
    {
    return n;
    }

    int operator[] (int index)
    {
    return k[index];
    }

    static Polynom sum(Polynom &a, Polynom &b)
    {
    int i;
    int* k;
    int n;
    n = max(a.rank(), b.rank());
    k = (int*) malloc(n * sizeof(int));
    for (i = 0; i < n; i++)
    {
    k[i] = 0;
    if (i < a.rank())
    {
    k[i] += a[i];
    }
    if (i < b.rank())
    {
    k[i] += b[i];
    }
    }
    Polynom c(n, k);
    free(k);
    return c;
    }

    void Print()
    {
    int i;
    for (i = 0; i < n; i++)
    {
    if (i)
    {
    printf("+ ");
    }
    printf("%d * a ^ %d ", k[n - i - 1], n - i - 1);
    }
    printf("\r\n");
    }

    private:
    int* k;
    int n;
    };

    int main()
    {
    int k[10];

    k[0] = 1;
    k[1] = -2;
    k[2] = 1;
    Polynom a(3, k);
    k[0] = -1;
    k[1] = 1;
    Polynom b (2, k);
    Polynom res(Polynom::sum(a, b));
    res.Print();
    return 0;
    }
    Все равно это говнокод. Плохо. Я б на месте препода негодовал.

    Добавлено:
    Очень просто такое происходит. Ты используешь, видимо, компилятор майкрософта.

    дебаг и релиз - это совсем разные штуки и работают они по-разному. Но если ты пишешь более менее нормальный код - то и поделки майкрософта сработают предсказуемо (их уже отладили на этом), но если же ты говнокодишь, да так, что гейтс представить себе такого не может, то кнешно компилятору майкрософта ничего не остается кроме как ориентироваться на пятна на солнце, да фазу луны.

    Используй уже gcc и прочитай нормальные книжки по плюсам (ссылки есть на форуме, я лично за ними слежу :D ) - http://codeby.net/forum/threads/51900.html
     
  3. Vadik(R)

    Vadik(R) Well-Known Member

    Регистрация:
    12 дек 2007
    Сообщения:
    483
    Симпатии:
    0
    r04, приношу свои извинения. Я только сейчас увидел, что Вы код подправили. До этого думал, Вы просто процитировали его.

    Насчёт статической функции sum - понял. Вполне понимал, что быдлокод. Но не думал, что настолько, что будет вылетать. А вот про то, что "нельзя просто так взять и присвоить" - никак не могу успокоиться.
    Неужели между:
    Код (C++):
    Polynom c(n, k);
    и:
    Код (C++):
    Polynom c;
    c = Polynom(n, k);
    есть разница, и ещё большая?

    Почему нельзя просто взять и присвоить? Как же тогда работают всякие QString?
    Мы же всегда может сделать, что-то типа:
    QString str1;
    QString str2;
    QString str3;
    str1 = "a";
    str2 = "b";
    str3 = str1 + str2;

    Тут же ничего не вылетает. И присваивается объект в случае str3 = str1 + str2. Или я чего-то не понимаю?
    Согласен, потому и пришёл сюда за помощью, чтобы разобраться.
    К счастью препод уже не мой ;) После этой строчки может вы перестанете помогать, но это уже второй мой заказ, где я сталкиваюсь с этой проблемой, вот и заинтриговало самого :D
    По логике, она должна складывать два полинома и возвращать третий. Ну, как аналог str3 = str1 + str2.

    Так мне в итоге как тогда стоило поступить? Для меня откровением стало уже:
    Как же быть? У меня единственный выход - только создание указателя на класс чтоль?
    С sum попозже разберусь, вначале это интересует :)
     
  4. Vadik(R)

    Vadik(R) Well-Known Member

    Регистрация:
    12 дек 2007
    Сообщения:
    483
    Симпатии:
    0
    r04, к сожалению, в Вашем код проблема по-прежнему осталась. Вот, даже сделал небольшую отладку:
    Код (C++):
    Start constructor(n, k)
    id = a
    k = 00E127F0
    End constructor(n, k)

    Start constructor(n, k)
    id = b
    k = 00E1C1B8
    End constructor(n, k)

    Start constructor(n, k)
    id = c
    k = 00E1C260
    End constructor(n, k)

    Start free k
    id = c
    k = 00E1C260
    End free k

    Start free k
    id = c
    k = 00E1C260
    На данный момент код таков:
    Код (C++):
    #include <iostream>
    #include <locale>
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>

    using namespace std;

    char c;

    int max(int a, int b)
    {
    return a > b ? a : b;
    }

    class Polynom
    {
    public:
    Polynom()
    {
    cout << "Start constructor()" << endl;
    d = c++;
    n = 1;
    k = (int*) malloc(n * sizeof(int));
    k[0] = 0;
    cout << "id = " << d << endl;
    cout << "k = " << this->k << endl;
    cout << "End constructor()" << endl << endl;
    }

    Polynom(int n, int k[])
    {
    cout << "Start constructor(n, k)" << endl;
    d = c++;
    this->n = n;
    this->k = (int*) malloc(this->n * sizeof(int));
    memcpy(this->k, k, this->n * sizeof(int));
    //for (int i = 0; i < n; i++)
    //  cout << this->k[i] << " " << k[i] << endl;
    cout << "id = " << d << endl;
    cout << "k = " << this->k << endl;
    cout << "End constructor(n, k)" << endl << endl;
    }

    Polynom& operator=(Polynom &other)
    {
    cout << "Start operator=" << endl;
    //free(this->k);
    this->n = other.n;
    this->k = (int*) malloc(this->n * sizeof(int));
    memcpy(this->k, other.k, this->n * sizeof(int));
    //memcpy(&(this->k), &(other.k), this->n * sizeof(int));
    //cout << this->k << endl;
    //cout << other.k << endl;
    cout << "id = " << d << endl;
    cout << "k = " << this->k << endl;
    cout << "End operator=" << endl << endl;
    return *this;
    }

    ~Polynom()
    {
    cout << "Start free k" << endl;
    cout << "id = " << d << endl;
    cout << "k = " << this->k << endl;
    free(k);
    cout << "End free k" << endl << endl;
    }

    int rank()
    {
    return n;
    }

    int operator[] (int index)
    {
    return k[index];
    }

    static Polynom sum(Polynom &a, Polynom &b)
    {
    int i;
    int* k;
    int n;
    n = max(a.rank(), b.rank());
    k = (int*) malloc(n * sizeof(int));
    for (i = 0; i < n; i++)
    {
    k[i] = 0;
    if (i < a.rank())
    {
    k[i] += a[i];
    }
    if (i < b.rank())
    {
    k[i] += b[i];
    }
    }
    Polynom c(n, k);
    free(k);
    return c;
    }

    void Print()
    {
    int i;
    for (i = 0; i < n; i++)
    {
    if (i)
    {
    printf("+ ");
    }
    printf("%d * a ^ %d ", k[n - i - 1], n - i - 1);
    }
    printf("\r\n");
    }

    private:
    char d;
    int* k;
    int n;
    };

    int main()
    {
    c = 'a';
    int k[10];
    k[0] = 1;
    k[1] = -2;
    k[2] = 1;
    Polynom a(3, k);
    k[0] = -1;
    k[1] = 1;
    Polynom b(2, k);
    //Polynom::sum(a, b);
    Polynom res(Polynom::sum(a, b));
    //Polynom res;
    //res = Polynom::sum(a, b);
    //res.Print();
    return 0;
    }
    Замечу только, что он становится рабочем и в дебаге и вызывает один деструктор при таком сочетании:
    Код (C++):
    static Polynom& sum(Polynom &a, Polynom &b)
    ...
    Polynom::sum(a, b);
    То есть, sum возвращает ссылку. А Ваш случай, к сожалению, по-прежнему ошибку вызывает, почему-то для одного и того же объекта деструктор вызывается два раза ;)
     
  5. Vadik(R)

    Vadik(R) Well-Known Member

    Регистрация:
    12 дек 2007
    Сообщения:
    483
    Симпатии:
    0
    Ещё один update. Присваивания всё-таки работают:
    Код (C++):
    #include <iostream>
    #include <locale>
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>

    using namespace std;

    char c;

    int max(int a, int b)
    {
    return a > b ? a : b;
    }

    class Polynom
    {
    public:
    Polynom()
    {
    cout << "Start constructor()" << endl;
    d = c++;
    n = 1;
    k = (int*)malloc(n * sizeof(int));
    k[0] = 0;
    cout << "id = " << d << endl;
    cout << "k = " << this->k << endl;
    cout << "End constructor()" << endl << endl;
    }

    Polynom(int n, int k[])
    {
    cout << "Start constructor(n, k)" << endl;
    d = c++;
    this->n = n;
    this->k = (int*)malloc(this->n * sizeof(int));
    memcpy(this->k, k, this->n * sizeof(int));
    //for (int i = 0; i < n; i++)
    //  cout << this->k[i] << " " << k[i] << endl;
    cout << "id = " << d << endl;
    cout << "k = " << this->k << endl;
    cout << "End constructor(n, k)" << endl << endl;
    }

    Polynom& operator=(Polynom &other)
    {
    cout << "Start operator=" << endl;
    //free(this->k);
    this->n = other.n;
    this->k = (int*)malloc(this->n * sizeof(int));
    memcpy(this->k, other.k, this->n * sizeof(int));
    //memcpy(&(this->k), &(other.k), this->n * sizeof(int));
    //cout << this->k << endl;
    //cout << other.k << endl;
    cout << "id = " << d << endl;
    cout << "k = " << this->k << endl;
    cout << "End operator=" << endl << endl;
    return *this;
    }

    ~Polynom()
    {
    cout << "Start free k" << endl;
    cout << "id = " << d << endl;
    cout << "k = " << this->k << endl;
    free(k);
    cout << "End free k" << endl << endl;
    }

    int rank()
    {
    return n;
    }

    int operator[] (int index)
    {
    return k[index];
    }

    static Polynom sum(Polynom &a, Polynom &b)
    {
    int i;
    int* k;
    int n;
    n = max(a.rank(), b.rank());
    k = (int*)malloc(n * sizeof(int));
    for (i = 0; i < n; i++)
    {
    k[i] = 0;
    if (i < a.rank())
    {
    k[i] += a[i];
    }
    if (i < b.rank())
    {
    k[i] += b[i];
    }
    }
    Polynom c(n, k);
    free(k);
    return Polynom(c.n, c.k);
    //return c;
    }

    void Print()
    {
    int i;
    for (i = 0; i < n; i++)
    {
    if (i)
    {
    printf("+ ");
    }
    printf("%d * a ^ %d ", k[n - i - 1], n - i - 1);
    }
    printf("\r\n");
    }

    private:
    char d;
    int* k;
    int n;
    };

    int main()
    {
    c = 'a';
    int k[10];
    k[0] = 1;
    k[1] = -2;
    k[2] = 1;
    Polynom a(3, k);
    k[0] = -1;
    k[1] = 1;
    Polynom b(2, k);
    //Polynom::sum(a, b);
    //Polynom res(Polynom::sum(a, b));
    Polynom res;
    res = Polynom::sum(a, b);
    res.Print();
    return 0;
    }
    А ключевым моментом оказалось вот:
    Код (C++):
    ...
    Polynom c(n, k);
    free(k);
    return Polynom(c.n, c.k);
    //return c;
    ...
    Оказывается, просто имеет очень большое значение, что мы возвращаем. Если возвращаем локальную переменную-объект, то всё рушится. А если возвращаем Polynom(параметры), то работает!!! ;)
    Скажем так, проблему можно считать частично решённой. Частично - потому что понял, как поступать. А не понял, с чего вдруг какая-то есть разница в строчках:
    Код (C++):
            return Polynom(c.n, c.k);
    //return c;
     
  6. rrrFer

    rrrFer Well-Known Member
    Команда форума C\C++ Team

    Регистрация:
    6 сен 2011
    Сообщения:
    1.324
    Симпатии:
    36
    Выкинь свой компилятор, я ж говорил.
    Функция у тебя возвращает результат по значению, это значит, что будет вызван конструктор копирования. (в любом случае - не важно локальная это переменная {первый вариант} или временный объект {второй вариант}).
    Ну еще, в зависимости от компилятора эти моменты могут как-то оптимизироваться - дело может быть в этом. Но

    Если такие присваивания, как у тебя, работают - то компилятор твой не работает.

    В соседней теме ты про билдер спрашиваешь. Ты на нем и пишешь?
     
  7. rrrFer

    rrrFer Well-Known Member
    Команда форума C\C++ Team

    Регистрация:
    6 сен 2011
    Сообщения:
    1.324
    Симпатии:
    36
    В первом случае вызывается конструктор с двумя аргументами. Больше ничего не вызывается.

    Во втором, вызывается конструктор по умолчанию (без параметров), затем вызывается конструктор с двумя аргументами (и создается временный объект), затем, вызывается оператор присваивания.

    На присваивании нормальный компилятор выдаст ошибку:
    Потому что аргумент оператор присваивания у тебя получает по ссылке, но ты передаешь туда временный объект (это значение) и следовательно, он не может преобразовать Polynom в Polynom&.

    Qt не так прост. Всегда можно посмотреть исходники:
    inline QString(); //1
    QString(QChar c); //2
    QString &operator=(QChar c); // 3
    QString &operator=(const QString &); // 4
    #ifdef Q_COMPILER_RVALUE_REFS
    inline QString(QString && other) : d(other.d) { other.d = Data::sharedNull(); } //5
    inline QString &operator=(QString &&other) // 6
    { qSwap(d, other.d); return *this; }
    #endif
    inline const QString operator+(const QString &s1, const QString &s2) // 6
    { QString t(s1); t += s2; return t; }

    Сначала будет 3 раза вызван конструктор по умолчанию (1), затем 2 раза конструктор QChar (3), затем оператор + (6), а после этого, как мне кажется, перемещающий конструктор (5).

    МОжет быть я не прав.

    Добавлено: вообще, твой код кривой.
    Не должна функция sum возвращать объект по значению.
    Возвращай либо ссылку, либо указатель.
     
  8. Vadik(R)

    Vadik(R) Well-Known Member

    Регистрация:
    12 дек 2007
    Сообщения:
    483
    Симпатии:
    0
    Не, в той теме я наоборот ответил (если Вы про эту), я даже и не заметил, что там Builder. Пишу на Visual Studio в основном. Есть ещё на ubuntu gcc, только там пока очень простенькие программы пишу.
    В любом случае Вам спасибо ;) Есть какая-то моральная поддержка, что вообще есть ответы в теме :D Посмотрю в сторону других компиляторов

    Добавлено
    Ещё только что заметил ещё одну странность MS VS 2013:
    Код (C++):
    .....
    sum
    ....
    Polynom *c = new Polynom(n, k);
    free(k);
    return *c;
    То деструктор для *c всё равно вызывается, и утечек памяти не будет. Причём и код отработает без вылетов. Ну опять же, тогда свалим всё на причуды выжуалки
     
  9. rrrFer

    rrrFer Well-Known Member
    Команда форума C\C++ Team

    Регистрация:
    6 сен 2011
    Сообщения:
    1.324
    Симпатии:
    36
    Ну я не знаю...

    Когда я учился в ВУЗе, нас ваще гоняли по BC3.1 (это такая древняя синяя хреновина, задуманная еще в начале 90х или конце 80х) - сейчас ее не дают вроде бы потому, что не запускается она на новых windows даже в режиме совместимости.

    Дак вот там можно было делать так:

    char *s;
    scanf("%s", s);

    Т.е. память под строки можно было не выделять. Это касалось именно строк, с другими массивами не канало. По легенде, ВС3.1 выделял как-то сам какой-то объем памяти (не известно какой) под строки ;). Я не знаю надо было освобождать эту память или нет. Сейчас я думаю, что может быть и не выделялось там ничего, просто по указателю выделялась память (он ведь тоже адрес имеет) и все это должно было приводить к крэшам (но мы их не наблюдали ни разу, мало того, в наших методичках примеры были такие же).

    Опиши тут задачу (задание, которое решал), может быть я найду время и отвечу как бэ это могло выглядеть с моей точки зрения (она далека от идеала, но все же)
     
  10. Vadik(R)

    Vadik(R) Well-Known Member

    Регистрация:
    12 дек 2007
    Сообщения:
    483
    Симпатии:
    0
    Задание в оригинале было так:
    Выкладывая код, решил локализовать проблему, поэтому оставил только метод sum.
     
Загрузка...
Похожие Темы - Debag Release
  1. d7uk4r3v
    Ответов:
    16
    Просмотров:
    481
  2. SvetlanaL
    Ответов:
    0
    Просмотров:
    476
  3. alsav22
    Ответов:
    5
    Просмотров:
    2.484
  4. Akupaka
    Ответов:
    83
    Просмотров:
    37.479

Поделиться этой страницей