CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Błędy przy typach tekstowych używanych w strukturach dynam.

Błędy przy typach tekstowych używanych w strukturach dynam.

dział ogólny

Błędy przy typach tekstowych używanych w strukturach dynam.

Nowy postprzez lukagrom » wtorek, 5 listopada 2019, 17:11

Przez przypadek "odkryłem", że nasz ulubiony kompilator dostaje zawiechy (niezależnie od wersji) kiedy użyjemy jakiejś dynamicznej tablicy struktur (tworzonych i usuwanych parą (new idelete), jeżeli w takiej strukturze wystąpi typ tekstowy w zależności od wersji - AnsiString UnicodeString
Prosty przykład, tablica dynamiczna struktury o rozmiarze 2;
KOD cpp:     UKRYJ  
struct date_String
 {
  AnsiString name;
  int age;
  float salary;
 };
 date_String *my_record_String=new struct date_String[2];
 my_record_String[0].name="John Rambo";
 my_record_String[0].age=50;
 my_record_String[0].salary=20101.76;
 my_record_String[1].name="Don Johnson";
 my_record_String[1].age=47;
 my_record_String[1].salary=343431.23;
 delete my_record_String;
 

Kompiluje się ok, jednak uruchomienie zawiesza już system. Kluczem/powodem do wywalenie systemu jest użycie - delete.
Ta sama struktura z użyciem zamiast AnsiString UnicodeString zwykłego char* nie powoduje żadnych błędów wykonawczych.
KOD cpp:     UKRYJ  
struct Date
 {
  char  *name;
  int age;
  float salary;
 };
 Date *my_Record=new struct Date[2];
...
delete my_Record;
 

Z kolei nie ma też błędów w działaniu, gdy struktura dynamiczna, która posiada dane (AnsiString UnicodeString) będzie jednowymarowa, bądz będzie zadeklarowana statycznie:
KOD cpp:     UKRYJ  
date_String my_record_String[2];
 my_record_String[0].name="John Rambo";
 my_record_String[0].age=50;
 my_record_String[0].salary=20101.76;
 my_record_String[1].name="Don Johnson";
 my_record_String[1].age=47;
 my_record_String[1].salary=343431.23;
 

Wychodzi na to, że para AnsiString UnicodeString nie powinna być za bardzo umieszczana w strukturach/rekordach gdzie występuję - delete
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 123
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    Windows VistaChrome

Re: Błędy przy typach tekstowych używanych w strukturach dynam.

Nowy postprzez lukagrom » wtorek, 5 listopada 2019, 17:19

Uściślając jeszcze sam typ (AnsiString UnicodeString) nie "ma problemów" z new - delete o ile nie występuje w strukturach.
Samo użycie typów tekstowych działa bezkolizyjnie:
KOD cpp:     UKRYJ  
UnicodeString *planets=new UnicodeString[3];
 planets[0]="Earth";
 planets[1]="Mercury";
 planets[2]="Jupiter";
 delete planets;
 
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 123
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    Windows VistaChrome

Re: Błędy przy typach tekstowych używanych w strukturach dynam.

Nowy postprzez polymorphism » wtorek, 5 listopada 2019, 19:42

Przez przypadek "odkryłem", że nasz ulubiony kompilator dostaje zawiechy

Nie kompilator, tylko twój program. Masz tam błąd. Tak powinno być:
KOD cpp:     UKRYJ  
date_String *my_record_String = new date_String[2];
...
delete[] my_record_String;

Tablice powinieneś usuwać wyrażeniem delete[].

Gdybyś od razu użył std::vector, to nie miałbyś problemów.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2263
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 210
System operacyjny: Windows 8.1
Windows 10
Linux Mint 19
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    UbuntuFirefox

Re: Błędy przy typach tekstowych używanych w strukturach dynam.

Nowy postprzez lukagrom » wtorek, 5 listopada 2019, 20:31

Sorry, rzeczywiście. Zmyliłem się tym, że gdy w strukturze był char* wystarczyło użyć samo delete nazwaStruktury, jakby nie patrzyć jest to jakaś anomalia, że dla jednych danych wystarczy samo - delete Nazwa, a dla innych danych z kolei - delete[] Nazwa
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 123
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    Windows VistaChrome

Re: Błędy przy typach tekstowych używanych w strukturach dynam.

Nowy postprzez lukagrom » wtorek, 5 listopada 2019, 21:01

A właściwie dlaczego kompilowano są zarówno programy z delete nazwa_Struktury i delete [] nazwa_Struktury? Jakby nie patrzeć dwie różne konstrukcje. Na linuksowym gcc/g++ próbowałem w obu wariantach i w każdym się program kompilował się i uruchamiał. Chyba trzeba się przyjrzeć jakimś podręcznikom jak właściwie działają - new - delete
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 123
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    Windows VistaChrome

Re: Błędy przy typach tekstowych używanych w strukturach dynam.

Nowy postprzez polymorphism » wtorek, 5 listopada 2019, 21:08

jakby nie patrzyć jest to jakaś anomalia,

Żadna anomalia. Żeby zrozumieć błąd, trzeba zrozumieć, jak działa delete[].

W uproszczeniu delete[] działa tak:
KOD cpp:     UKRYJ  
date_String *p = new struct date_String[2];


// delete[] p;
size_t n = reinterpret_cast<size_t*>(p)[-1];
for(size_t i = 0; i < n; ++i) p[i].~date_String();
free(reinterpret_cast<size_t*>(p) - 1);

Czyli przed zwolnieniem pamięci wywołuje destruktory wszystkich klas będących w tablicy.

Zwykłe delete robi coś takiego:
KOD cpp:     UKRYJ  
p->~date_String();
free(p);

Jeśli jesteś spostrzegawczy, to zapewne zauważysz, że gdy dasz zwykłe delete dla tablicy, to free dostanie nieprawidłowy adres pamięci. Stąd ten błąd.

Teraz, dlaczego struktura ze wskaźnikami char* działa, a z AnsiStringiem nie? Dzieje się tak dlatego, ponieważ struktura ze wskaźnikami jest tzw. POD-em. Dla POD-ów kompilator nie robi rozróżnienia na detele/delete[], bo POD-y nie zawierają destruktorów, które trzeba by wywoływać w pętli. A skoro tak, to nie ma potrzeby zapisywać wielkości tablicy na ujemnym indeksie, free dostanie prawidłowy adres pamięci do zwolnienia.

To tak pokrótce.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2263
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 210
System operacyjny: Windows 8.1
Windows 10
Linux Mint 19
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    UbuntuFirefox

Re: Błędy przy typach tekstowych używanych w strukturach dynam.

Nowy postprzez lukagrom » wtorek, 5 listopada 2019, 21:29

Może dlatego ci z Microsoftu tworząc C++/CLI dla Visual C++ stworzyli konstrukcję gcnew, która sprowadza się do sytuacji: użyj i zapomnij, gdzie żaden odpowiednik free/delete nie jest nigdy wymagany.
Swoją drogą co ma takiego atrakcyjnego w sobie new delete, czego nie ma malloc free?
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 123
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    Windows VistaChrome

Re: Błędy przy typach tekstowych używanych w strukturach dynam.

Nowy postprzez polymorphism » wtorek, 5 listopada 2019, 21:44

Może dlatego ci z Microsoftu tworząc C++/CLI dla Visual C++ stworzyli konstrukcję gcnew

Nie, gcnew wprowadzili tylko po to, by zachować zgodność z .NET, które powstało głównie dla C# (czyli języka zarządzanego, z garbage collectorem).

gdzie żaden odpowiednik free/delete nie jest nigdy wymagany.

We współczesnym C++ możesz praktycznie do zera zredukować konieczność używania new/delete. Masz std::unique_ptr, std::shared_ptr i std::vector, więcej Ci nie potrzeba. Dzisiaj ręczne zarządzanie pamięcią (poza wyjątkami) to przejaw złego stylu i amatorki.

Swoją drogą co ma takiego atrakcyjnego w sobie new delete, czego nie ma malloc free?

Przyjrzyj się kodom, które podałem. malloc i free, funkcje wzięte z C, nie wywołują konstruktorów i destruktorów klas. Dlatego wprowadzono new/delete.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2263
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 210
System operacyjny: Windows 8.1
Windows 10
Linux Mint 19
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    UbuntuFirefox


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 15 gości

cron