Различное поведение в Visual C ++ по сравнению с MingW - PullRequest
1 голос
/ 08 марта 2012

У меня есть класс-оболочка для int с именем intWrapper и функция addN, которая добавляет два числа, определяемых следующим образом:

intWrapper* addN(intWrapper *first, intWrapper *second)
{
    intWrapper c;
    c.setData(first->getData() + second->getData());
    return &c;
}

Затем в функции main () я делаю это:

intWrapper first(20), second(40);
intWrapper* t = addN(&first, &second);
cout << (*t).getData() << endl;

В Dev-c ++ (MingW32) это выполняется должным образом и выводит значение 60, но в Visual C ++ я получаю значение -858993460.
Однако, если я использую ключевое слово new для создания нового объекта внутри функции addN, оно выводит 60 также в Visual C ++. Я заинтригован относительно того, почему это происходит. Есть мысли?
Полный код здесь:

#include <iostream>
using namespace std;

template<typename T, T defaultValue>
class Wrapper
{
      private: T n_;
      public:
             Wrapper(T n = defaultValue) : n_(n) {}
             T getData()
             {
                  return n_;
             }
             void setData(T n)
             {
                  n_ = n;
             }
};

typedef Wrapper<int, 47> intWrapper;

intWrapper* addN(intWrapper *first, intWrapper *second)
{
   intWrapper c;
   c.setData(first->getData() + second->getData());
   return &c;
}

int main()
{
    intWrapper p;
    cout << p.getData() << endl;
    intWrapper first(20), second(40);
    intWrapper* t = addN(&first, &second);
    cout << (*t).getData() << endl;
    system("PAUSE");
    return 1;
}

Ответы [ 2 ]

7 голосов
/ 08 марта 2012

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

Неопределенное поведение означает что-либоможет произойти: может произойти сбой, может показаться, что он «работает» правильно или может работать неправильно.

Когда вы используете new, экземпляр intWrapper будет находиться за рамками функции и не будет неопределеннымповедение и будет работать правильно (как для VC, так и для MingW32).Не забудьте delete вернуть intWrapper*, когда больше не требуется.

0 голосов
/ 08 марта 2012

В Dev-c ++ (MingW32) это выполняется как задумано

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

Вы возвращаете указатель на локальную переменную.Локальная переменная перестает существовать, когда вы возвращаетесь из функции.Это означает, что память, ранее использовавшаяся этой переменной, могла содержать что-нибудь или могла бы даже больше не читаться (то есть вы получите segfault / access access).Если вы не любите играть в русскую рулетку и не хотите абсолютно непредсказуемого поведения в вашей программе, вам не следует этого делать.

Либо возвращайте IntWrapper по значению (для этого вам понадобится конструктор копирования и оператор присваивания):

intWrapper addN(intWrapper *first, intWrapper *second)
{
    intWrapper c;
    c.setData(first->getData() + second->getData());
    return c;
}

, или выделите его с помощью new, а затем верните результат (и забудьте об этом позже)

intWrapper* addN(intWrapper *first, intWrapper *second)
{
    intWrapper *c = new intWrapper;
    c->setData(first->getData() + second->getData());
    return c;
}

Или используйте умный указатель (shared_ptr), чтобы удалить его автоматически.

...