почему это показывает ошибку времени выполнения в ideone & visual studio, а не в блоках кода?

0

Почему следующий код показывает ошибку времени выполнения в Ideone, а также в визуальной студии, но не в блоках кода?

#include <iostream>
using namespace std;

class myclass{
int *p;
public:
myclass(int i)
{p=new int;
 *p=i;}
~myclass(){delete p;}
int *get(){return p;}
};

void show (myclass x){
int *i=x.get();
cout<<*i<<endl;
}

int main() {
myclass a(19);
show (a);
return 0;
}

И я также не знаю, что не так с этим кодом (ошибка времени выполнения как в идеоне, так и в visual studio, но не в блоках кода)

#include <iostream>
using namespace std;
int main() {
int *i=new int ;
int j=19;
i=&j;
cout<<*i<<endl;
delete i;
return 0;
}

У меня есть догадка в первом случае память p удаляется один раз в функции show(), а затем снова после main(), поэтому удаление такой же памяти может вызвать эту ошибку времени выполнения (я не уверен, хотя, будь то случай или нет, PLS объяснить почему) и использование ссылки в void show (myclass & x) действительно устранили ошибку, но я не вижу, что изменилось, а во втором случае я думаю, что ошибка использует адрес j, если назначено значение j, ошибка исчезнет, но в обоих случаях блоки кода не показали мне какой-либо ошибки, поэтому, если кто-либо сможет разъяснить это поведение компилятора, это будет очень заметно (жаль для публикации такого длинного вопроса). Thnks заранее.

  • 0
    Вы хотите сказать, что в обоих случаях при запуске его в Code :: Blocks код выполняется до завершения? Не могу поверить в это, так как IDE не имеет к этому никакого отношения.
  • 0
    хм, кодоблоки скомпилировали его и не выдавали никаких ошибок, даже ошибок времени выполнения при отображении результата на консоль, и нормально выходили при нажатии любой клавиши @SChepurin
Показать ещё 1 комментарий
Теги:
dynamic
runtime-error
reference
visual-studio-2012

3 ответа

1
Лучший ответ

Ваш класс управляет динамически распределенными ресурсами, но не соответствует правилу из трех. Ваш вызов для show включает в себя копию объекта myclass. Это приводит к тому, что два объекта "управляют" одной и той же памятью. Один из них уничтожается при выходе из show(), его ресурсы де-распределяются посредством вызова для delete в деструкторе. Это оставляет объект в main() удерживая указатель на выделенную память, которая затем пытается вызвать delete.

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

Суть в том, что если вашему классу необходимо управлять ресурсами (и это важно, если), то следуйте правилу из трех (или пяти в С++ 11).

1

Итак, это типичный случай "неопределенного поведения". И да, в вашем примере myclass, p удаляется дважды, что и вызывает проблемы. Во втором случае вы просто удаляете указатель, который не был назначен new, что означает, что вы не следуете правилам, как вам следует.

Неопределенное поведение - это то, где C и C++ (и другие языки) объясняют, что происходит, говоря "он не определен". Спецификация делает это, чтобы избежать необходимости исключать или делать дорогостоящие обходные пути на оборудовании, которое/не имеет определенного поведения - например, если стандарт C++ сказал, что "среда выполнения C++ должна обнаруживать delete памяти, которая hasn 't было выделено new ", было бы очень сложно написать delete которое делает правильную вещь (вы можете подумать, что это не слишком сложно, а для данной архитектуры это может быть не так, но в 16-разрядном микроконтроллере, это может добавить значительные накладные расходы. Поскольку одним из основных принципов C или C++ является "вы не платите за то, что не просили", такие накладные расходы были бы неприемлемы. [Неважно, схема не может быть сделана на 100% безопасной, так как всегда возможно, что указатель может быть "поддельным" и по-прежнему соответствовать всем проверкам, которые были сделаны каким-то образом].

0

Вам нужно перегрузить конструктор копирования.

void show (myclass x){ 
int *i=x.get(); // here x.p points to same location as a.p
cout<<*i<<endl;
}
//here x.p is deleted in the destructor for x and so is a.p.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню