• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Uproszczenie kodu, pytanie o UB i celowość funkcji

–1 głos
270 wizyt
pytanie zadane 26 września 2020 w C i C++ przez NewEraOfPeace Gaduła (4,790 p.)

Cześć.
Szukając dzisiaj demanglera do C++ (bo trafiały się fajne krzaczki), znalazłem na SO ten kod:
 

std::string demangle(const char* mangled)
{
      int status;
      std::unique_ptr<char[], void (*)(void*)> result(
        abi::__cxa_demangle(mangled, 0, 0, &status), std::free);
      return result.get() ? std::string(result.get()) : "error occurred";
}

Pobawiłem się nim trochę i nasuwają mi się dwa pytania.

  1. Czy nie można krócej i prościej zrobić tego tak (może tu jest jakiś UB?) ?
    std::string demangle(const char* mangled){
          int status;
          std::unique_ptr<char[]> result(abi::__cxa_demangle(mangled, 0, 0, &status));
    
          return !status ? result.get() : "error occurred";
    }

    2. Czemu gdy w pierszym argumencie do template'a unique_ptr dam char*, zamiast char[] dostaję no matching function for call ...? Z tego co widziałem, to abi::cxx__demangle zwraca char*

1 odpowiedź

0 głosów
odpowiedź 26 września 2020 przez j23 Mędrzec (195,220 p.)

może tu jest jakiś UB? ?

Jest. std::unique_ptr domyślnie używa delete do zwalniania pamięci, abi::__cxa_demangle zwraca pamięć, która powinna być zwolniona funkcją free.

Czemu gdy w pierszym argumencie do template'a unique_ptr dam char*, zamiast char[]

Jak dasz char*, to result będzie oczekiwał wartości typu char**, dlatego powinieneś dać char jako parametr szablonu.

komentarz 26 września 2020 przez tkz Nałogowiec (42,040 p.)
Dlaczego powinna być zwolniona przy użyciu free? Niby w linku poniżej znajduje się również taki zapis... Ale jaka będzie różnica z delete?
https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html
komentarz 26 września 2020 przez j23 Mędrzec (195,220 p.)

The caller is responsible for deallocating this memory using free.

komentarz 26 września 2020 przez tkz Nałogowiec (42,040 p.)
Miałem na myśli, dlaczego nie mogę użyć delete zamiast free.
komentarz 26 września 2020 przez j23 Mędrzec (195,220 p.)

Standard nie mówi, że delete zawsze używa funkcji free do zwalniania pamięci. Zatem jest to UB.

komentarz 26 września 2020 przez NewEraOfPeace Gaduła (4,790 p.)

Jest. std::unique_ptr domyślnie używa delete do zwalniania pamięci, abi::__cxa_demangle zwraca pamięć, która powinna być zwolniona funkcją free.

Cóż to za specjalna pamięć, która potrzebuje specjalnego traktowania? Podasz jakiś link do tego mechanizmu, proszę?

Jak dasz char*, to result będzie oczekiwał wartości typu char**, dlatego powinieneś dać char jako parametr szablonu.

Chciałbym zauważyć, że został tam przekazany typ char[], a nie char* (a z tego co się orientuję, to jest to coś pokroju typu tablicowego). Z kolei cxx__demangle zwraca char*.

Kolejna rzecz - w sprawie UB myślałem również o zwracaniu łysego const char* z funkcji, która zwraca std::string, nie ma tam żadnej magii przez którą autor oryginalnego kodu mógłby się zdecydować jawnie robić z tego stringa?
 

komentarz 26 września 2020 przez j23 Mędrzec (195,220 p.)

Cóż to za specjalna pamięć, która potrzebuje specjalnego traktowania?

Zasada jest prosta: przydzielasz funkcją malloc, zwalniasz funkcją free. To samo z parami new / delete i new[] / delete[]. Łamiesz tę zasadę - masz UB.

Chciałbym zauważyć, że został tam przekazany typ char[], a nie char*

Ten char[] jest tam tylko po to, by była użyta specjalizacja std::unique_ptr dla tablic (która ma m.in. operator [] i domyślnie używa delete[]).

W tym konkretnym przypadku możesz dać std::unique_ptr<char> (byle z free).

Kolejna rzecz - w sprawie UB myślałem również o zwracaniu łysego const char* z funkcji, która zwraca std::string,

Tutaj nie ma UB.

komentarz 27 września 2020 przez NewEraOfPeace Gaduła (4,790 p.)

Zasada jest prosta: przydzielasz funkcją malloc, zwalniasz funkcją free. To samo z parami new / delete i new[] / delete[]. Łamiesz tę zasadę - masz UB.

Mógłbym prosić więcej informacji o tym? Jaki mechanizm za tym stoi? 

1
komentarz 28 września 2020 przez j23 Mędrzec (195,220 p.)

Przykładowy mechanizm może być taki: malloc przydzielając pamięć zapisuje w niej jakieś metadane, ergo - adres, który zwraca jest przesunięty o x bajtów metadanych. free to wie, więc będzie wiedzieć, że trzeba wskaźnik odpowiednio przesunąć do tyłu o te x bajtów, by uzyskać adres bazowy do zwolnienia. Problem pojawi się, gdy będziesz próbował zwolnić pamięć funkcją, które nie wie, że trzeba odpowiednio wyliczyć adres bazowy. Dostaniesz wyjątek, że próbujesz zwalniać pamięć, która nie została przydzielona.

Podobnie jest z delete i delete[] dla klas. new[] na ujemnym indeksie zapisuje wielkość tablicy, by delete[] wiedziało, dla ilu obiektów ma wywołać destruktor. I jeśli delete[] dostanie pamięć zwróconą przez new, to najprawdopodobniej będzie błąd.

Dlatego jak masz napisane w dokumentacji, że masz użyć takiej a nie innej funkcji do zwolnienia pamięci, to tak ma być.

Podobne pytania

0 głosów
1 odpowiedź 209 wizyt
pytanie zadane 29 kwietnia 2020 w C i C++ przez ShockWave Bywalec (2,350 p.)
–1 głos
1 odpowiedź 256 wizyt
pytanie zadane 9 lutego 2019 w Java przez Pioter_94 Nowicjusz (120 p.)
0 głosów
2 odpowiedzi 950 wizyt
pytanie zadane 17 listopada 2018 w Matematyka, fizyka, logika przez Nowicjusz2018 Nowicjusz (240 p.)

93,599 zapytań

142,524 odpowiedzi

322,993 komentarzy

63,082 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Kursy INF.02 i INF.03
...