Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> где логика работы с указателями? кто знает ответ? 
:(
    Опции темы
yours-tester
Дата 6.2.2005, 14:47 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Начал изучать C++ с помощью VC6++ на winXP
Не могу найти ответ на интересующий меня вопрос.
Разобрал пример и он привёл меня в ступор.
А правильно ли я выбрал язык на котором хочу кое-что написать?
Что то какая то нелогичность получается в этом языке с указателями
пример приведён ниже, если не перегружать оператор присваивания
(закоментировать первый #define),
то после команды Str3=Str2=Str1
Str1.s, Str2.s, Str3.s - указывают на одну и ту же строку
но это ещё пол беды, когда после Str1.destroy() вызывается Str2.destroy()
происходит ошибка приложения и Windows пытается отослать в Microsoft
сообщение об ошибке. Оно понятно что, Str2.s уже указывает,
на освобождённую память, но неужели оператор delete этого не может распознать и
корректно отработать этот случай?
Что за этим разве программист должен следить?


Вот учебный пример

Код

#include <iostream.h>
#include <string.h>
#define OVERLOAD_ASSIGNMENT
class Str
{
char *s;
int len;
public:
void Initialize(const char*);
void Initialize() {s=NULL; len=0;}
void ToUpper() {strupr(s);}
void Destroy() {delete s; s=NULL; len=0;}
void print();
#ifdef OVERLOAD_ASSIGNMENT
Str& operator=(const Str&);
#endif
};

void Str::print()
{
if (s)
{cout << s <<endl;}
else
{ cout <<"NULL"<<endl;};

}

void Str::Initialize(const char* InitStr)
{
len=strlen(InitStr);
s=new char[len+1];
strcpy(s, InitStr);
}

#ifdef OVERLOAD_ASSIGNMENT
Str& Str::operator=(const Str& OtherStr)
{
len=OtherStr.len;
delete s;
s=new char[len+1];
strcpy(s,OtherStr.s);
return *this;
}
#endif

void main()
{
Str str1, str2, str3;
str1.Initialize("Hi! I am a strig!!!");
str2.Initialize();
str3.Initialize();
cout <<"After initialization: "<<endl;
cout <<"First object is "; str1.print();
cout <<"Second object is "; str2.print();
cout <<"Third object is "; str3.print();
str3=str2=str1;
cout <<"After assignment"<<endl;
cout <<"First object contains"; str1.print();
cout <<"Second object contains"; str2.print();
cout <<"Third object contains"; str3.print();
str3.ToUpper();
cout <<"All S3 to Upper" <<endl;
cout <<"First object contains"; str1.print();
cout <<"Second object contains"; str2.print();
cout <<"Third object contains"; str3.print();

str1.Destroy();
str2.Destroy();
str3.Destroy();

}




Это сообщение отредактировал(а) chipset - 6.2.2005, 20:14
  Вверх
S.A.P.
Дата 6.2.2005, 15:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2664
Регистрация: 11.6.2004

Репутация: 9
Всего: 71



Цитата(yours @ 6.2.2005, 14:47)
но неужели оператор delete этого не может распознать и корректно отработать этот случай?
наверняка в опциях компилятора можно выбирать проверку перед уничтожением, но я этим никогда не интересовался, да и зачем? Мы для того и вырали C++, чтобы все руками делать smile . Так быстрее работает. Хочешь писать программы с кучей скрытых ошибок, которые потом исполняющая среда за тобой будет подбирать, фиксить, но тормозить систему, выбирай Java или C#.
PM MAIL   Вверх
srd
Дата 6.2.2005, 15:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нереварин
**


Профиль
Группа: Участник Клуба
Сообщений: 951
Регистрация: 30.8.2003
Где: Владивосток

Репутация: 27
Всего: 49



Ну и? Повторное освобождение уже освобождённой памяти является грубейшей ошибкой в любом языке программирования, поддерживающем работу с указателями, в том числе и в тех, которые имеют сборщик мусора (типа явы или си шарпа). Всё просто и логично.
Добавлено @ 15:18
Цитата(Perchilla @ 6.2.2005, 23:15)
наверняка в опциях компилятора можно выбирать проверку перед уничтожением

Отладочная версия run-time может обнаруживать повторное освобождение памяти и выдавать исключение. Релизная версия будет молча ломать кучу, из-за чего баг будет вылазить совсем в другом месте.


--------------------
Не смей читать мою подпись!!!
PM MAIL Jabber   Вверх
Domestic Cat
Дата 6.2.2005, 20:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 3
Всего: 172



Цитата(srd @ 6.2.2005, 06:15)
в том числе и в тех, которые имеют сборщик мусора (типа явы или си шарпа). Всё просто и логично.


Не понял, как в менеджед языках можно повторно память освободить? smile


--------------------

PM   Вверх
chipset
Дата 6.2.2005, 20:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4071
Регистрация: 11.1.2003
Где: Seattle, US

Репутация: 27
Всего: 165



Перегрузи функцию delete и заставь её проверять NULL ли обьект перед удалением, и обнулять его в противном случае.
Мы так делаем smile
Добавлено @ 20:15
Так, на будущее... пользуйся плз тегами [code=cpp][/code], удобнее читать просто --Resize_Images_Alt_Text--

Это сообщение отредактировал(а) chipset - 6.2.2005, 20:15


--------------------
Цитата(Jimi Hendrix)
Well, I stand up next to a mountain
And I chop it down with the edge of my hand
PM MAIL WWW   Вверх
En_t_end
Дата 6.2.2005, 20:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2074
Регистрация: 4.12.2004

Репутация: 1
Всего: 20



Вообще фигня полная !!! smile
Первый раз вижу такую тупую реализацию!
PM MAIL ICQ Skype GTalk Jabber   Вверх
chipset
Дата 6.2.2005, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4071
Регистрация: 11.1.2003
Где: Seattle, US

Репутация: 27
Всего: 165



En_t_end, насчёт стиля ничего плохого сказать не могу...


--------------------
Цитата(Jimi Hendrix)
Well, I stand up next to a mountain
And I chop it down with the edge of my hand
PM MAIL WWW   Вверх
Конструктор
Дата 6.2.2005, 20:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 641
Регистрация: 12.5.2004
Где: Москва

Репутация: нет
Всего: 10



chipset, кажысь стандартная реализация и так проверяет не NULL-ли объект, тока сама в NULL не ставит при удалении. Вроде где то я читывал что по стандарту совершенно безопасно применить delete к NULL указателю
PM MAIL WWW ICQ   Вверх
yours-tester
Дата 6.2.2005, 20:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 56
Регистрация: 6.2.2005

Репутация: нет
Всего: нет



Вообще то здесь delete применяется не к NULL указателю, а к перекрёстному указателю, который не равен NULL, но указывает на уже освобождённую память.
Вопрос в том, есть ли способ узнать, что не NULL указатель указывает на освобождённую память.
И не освобождать её вторично.
Отладчик ведь откуда то об этом знает и покрасил мне переменные в красный цвет.
А оператор delete почему не может узнать этого?

PM MAIL   Вверх
Конструктор
Дата 6.2.2005, 22:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 641
Регистрация: 12.5.2004
Где: Москва

Репутация: нет
Всего: 10



А зачем ему? Ему скорость важна, а если не важна то как и было замечено Java и C#
PM MAIL WWW ICQ   Вверх
gepard
Дата 7.2.2005, 11:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2477
Регистрация: 29.2.2004

Репутация: 2
Всего: 40



Конструктор
Цитата
chipset, кажысь стандартная реализация и так проверяет не NULL-ли объект, тока сама в NULL не ставит при удалении. Вроде где то я читывал что по стандарту совершенно безопасно применить delete к NULL указателю

Ошибаешься...
yours-tester
Цитата
Вообще то здесь delete применяется не к NULL указателю, а к перекрёстному указателю, который не равен NULL, но указывает на уже освобождённую память.

Значит - NULL. Указатель - это как человек, который указывает на область памяти пальцем. Он тычит и говорит: "Вот здесь". А раз он NULL, то он - 0...0 - это NULL, NULL - это 0...
Если ты пишешь:
Код

str3 = str2 = str1;
...
str1.Destroy();
str2.Destroy();
str3.Destroy();

Это значит, что Человек с именем str3 тычет пальцем на область памяти, куда тычат str1 и str2.
Если ты удалил эту область, то получается, что тыкать-то им некуда.
str1.Destroy(); - парень с именем str1 перестаёт тыкать пальцем на область памяти.
str2.Destroy(), str3.Destroy(); - str2 и str3 рады перестать тыкать, но они уже перестали и второй раз перестать не могут... smile


--------------------
Когда начинаются цифровые войны, а траффик разносит моё сознание по бесконечным просторам инета, подобно ветру, разносящему листву по полям, тогда и только тогда я чувствую себя свободным!
© Я, Берсерк, что значит - Неистовый. 
PM MAIL WWW ICQ   Вверх
srd
Дата 7.2.2005, 11:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нереварин
**


Профиль
Группа: Участник Клуба
Сообщений: 951
Регистрация: 30.8.2003
Где: Владивосток

Репутация: 27
Всего: 49



Цитата(Domestic @ 7.2.2005, 03:11)
Не понял, как в менеджед языках можно повторно память освободить? smile

Ага, заврался я smile Имел в виду, что использование освобожденной памяти легко получить и в managed-языках. Т.е.:
Код

#include "stdafx.h"
#using <mscorlib.dll>
using namespace System;
__gc struct A
{
   int value;
};
int _tmain()
{
   A __gc *a = __gc new A;
   a->value = 5;
   a = 0;
   GC::Collect();
   GC::WaitForPendingFinalizers();
   a->value = 10;
return 0;
}

А вот повторного освобождения я не добился, как ни пытался.

Цитата
Цитата
 
chipset, кажысь стандартная реализация и так проверяет не NULL-ли объект, тока сама в NULL не ставит при удалении. Вроде где то я читывал что по стандарту совершенно безопасно применить delete к NULL указателю

Ошибаешься...

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

// можно писать так
int *a = 0;
delete a;
// или так
delete 0;




--------------------
Не смей читать мою подпись!!!
PM MAIL Jabber   Вверх
S.A.P.
Дата 7.2.2005, 12:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2664
Регистрация: 11.6.2004

Репутация: 9
Всего: 71



Цитата(srd @ 7.2.2005, 11:53)
Да нет, с точки зрения стандарта применять delete к нулевому указателя безопасно.
Код

// можно писать так
int *a = 0;
delete a;
// или так
delete 0;

На сколько я знаю, не во всех реализациях языка NULL есть 0. Поэтому для указателей лучше все таки использовать NULL. Стандарт языка гарантирует, что по адресу NULL ничего не будет и все операции с ним абсолютно безопасны. А delete 0 может не прокатить.
PM MAIL   Вверх
srd
Дата 7.2.2005, 12:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нереварин
**


Профиль
Группа: Участник Клуба
Сообщений: 951
Регистрация: 30.8.2003
Где: Владивосток

Репутация: 27
Всего: 49



Если мы говорим про Си++, то в стандарте есть понятие 0 как нулевого указателя, но нет ничего про NULL. Это просто наследине из Си-шной CRT. Более того, компилятор всегда может интерпретировать 0 как нулевой указатель, а вот NULL в разных реализациях может быть определён как 0, как (void *)0, как (long *)0 и т.п. Это может создать проблемы. Так что, что лучше - ещё вопрос.


--------------------
Не смей читать мою подпись!!!
PM MAIL Jabber   Вверх
gepard
Дата 7.2.2005, 14:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2477
Регистрация: 29.2.2004

Репутация: 2
Всего: 40



srd
Твоя правда...
Но только в том случае, если указатель точно "0".
Добавлено @ 14:54
Если delete вызывать после delete, то будет лаг...


--------------------
Когда начинаются цифровые войны, а траффик разносит моё сознание по бесконечным просторам инета, подобно ветру, разносящему листву по полям, тогда и только тогда я чувствую себя свободным!
© Я, Берсерк, что значит - Неистовый. 
PM MAIL WWW ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0596 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.