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

podwójne usunięcie pamięci

Object Storage Arubacloud
0 głosów
564 wizyt
pytanie zadane 26 stycznia w C i C++ przez TOWaD Mądrala (6,000 p.)

Wiem co, ale nie potrafię zrozumieć dlaczego, podmiana wskaźnika wywala program i jak to ominąć, by zwolnić nadmiarowa pamięć.

Otrzymuję komunikat  [w tym programie]

free(): double free detected in tcache 2

Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (no_tid=0, signo=6, threadid=140737348187968) at ./nptl/pthread_kill.c:44
44      ./nptl/pthread_kill.c: No such file or directory.

tak jakby podwójne wywołanie destruktora.

bignum::~bignum() {
    if(ptrlgnr)
        delete[]ptrlgnr;
    // o("usuniento")
}

powodem jest funkcja

void bignum::realloc(char * old,const size_t & newsize) {
    if(!old)
        throw std::bad_alloc();
    char* newone=nullptr;
    newone=new char[newsize+1] {};
    if(newone)
        for(size_t i=0; i<newsize; i++)
            newone[i]=old[i];
    else
        throw std::bad_alloc(); // jeżeli nie udała się rezerwacja pamięci.
    delete [] old;
    old=newone;
    newone=nullptr;
    return;

1 odpowiedź

+1 głos
odpowiedź 26 stycznia przez adrian17 Ekspert (345,160 p.)
wybrane 28 stycznia przez TOWaD
 
Najlepsza
Pierwsze co mi wyskakuje AddressSanitizerem to że wychodzisz poza pamięć, bo iterujesz się po `newsize` elementach, ale `old` może być mniejszy.

A po drugie, no, masz kompletnie źle kopiowanie obiektów. Operator przypisania nic nie robi, a konstruktora kopiującego w ogóle nie ma - więc pewnie kompilator stworzył domyślny, który po prostu kopiuje pola. A stąd już prosta droga do double free, bo można trywialnie i nawet przypadkiem dostać dwa obiekty wskazujące na ten char* i oba wywołają destruktory.

(btw, ten `new bignum` w operator+ też super dziwnie wygląda)
komentarz 26 stycznia przez TOWaD Mądrala (6,000 p.)

wychodzisz poza pamięć ... `newsize` elementach, ale `old` może być mniejszy

Używam do redukcji pamięci, wiec nie powinno ale dzięki za uwagę.


A stąd już prosta droga do double free, bo można trywialnie i nawet przypadkiem dostać dwa obiekty wskazujące.

Chciałem uniknąć głębokiej kopi i w ogóle uniknąć wnikania w temat konstruktora.

Ale ok napisze konstruktor kopiujący i zobaczymy co będzie.

Myślałem, że szybko uda mi się napisać nie standardowe odejmowanie a tu zonk.

Add działa "prawidłowo" tj dodaje dwie dodatnie liczby.

odejmowanie też, dopóki nie próbuje zredukować zajmowanej pamięci.


Operator przypisania nic nie robi

Ale też nie używam.


Dziwnie ?

zamiar był taki by add() używać do dodawania dwóch dodatnich liczb (I chciałem robić geterów i seterów) i używać przy też odejmowaniu,np 5-(-4)  a operator + to też miał dodawać np 5+(-4);

Czy to że kopię zwraca?

ps. i do wielu innych rzeczy mozna by się było przyczepić, ale to nie jest code review :).

1
komentarz 26 stycznia przez adrian17 Ekspert (345,160 p.)

Używam do redukcji pamięci, wiec nie powinno ale dzięki za uwagę.

Ale w tym konkretnym przypadku dokładnie tak się zdarzyło.

Ale też nie używam.

Nieważne. Standardową praktyką jest, że jak implementujesz destruktor, to też implementujesz konstruktor kopiujący i operator przypisania, bo z domyślnymi znowu - super łatwo o double free.

https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)

komentarz 26 stycznia przez TOWaD Mądrala (6,000 p.)

dokładnie tak się zdarzyło.

aaaa....

bignum operator - (const bignum& lhs,const bignum& rhs) {
    size_t size=(lhs.size>rhs.size)?lhs.size:rhs.size;
    bignum temp(std::string(std::max(lhs.size,rhs.size),'0'));
    int flag = 0b00;
    if(rhs.sign=='+')
        flag|=2;
    if(lhs.sign=='+')
        flag|=1;
//         o(bitset<4>(flag))
    if(temp.graterAbs(lhs,rhs)) //np |-5|>|4|=true
        switch(flag) {
            case 0:
                //  -5-(-4)= -(5-4)=-1
                temp.subtract(lhs,rhs);
                temp.sign='-';
                temp.realloc(temp.ptrlgnr,10);
                break;
            case 1:// oprzeciwnych znakach
                //5-(-4)= 5+4=9
                temp.add(lhs,rhs);
                break;
            case 2:// oprzeciwnych znakach
                //-5-4= -(5+4)=-9
                temp.add(lhs,rhs);
                temp.sign='-';
                break;
            case 3:// obie dodatnie
                //5-4= 5-4=1;
                temp.subtract(lhs,rhs);
                temp.realloc(temp.ptrlgnr,10);
                break;
            default:
                throw;
        } else //np |-4|>|5|=false
        switch(flag) {
            case 0:
                //  -4-(-5)= -(4-5)=(5-4)=1
                temp.subtract(rhs,lhs); //zmieniona kolejność funkcji
                // temp.sign='-';
                temp.realloc(temp.ptrlgnr,10);
                break;
            case 1:// oprzeciwnych znakach
                //4-(-5)= 4+5=9
                temp.add(rhs,lhs);//zmieniona kolejność funkcji
                break;
            case 2:// oprzeciwnych znakach
                //-4-5= -(5+4)=-9
                temp.add(rhs,lhs);//zmieniona kolejność funkcji
                temp.sign='-';
                break;
            case 3:// obie dodatnie
                //4-5= -(5-4)=-1;
                temp.subtract(rhs,lhs);//zmieniona kolejność funkcji
                temp.sign='-';
                temp.realloc(temp.ptrlgnr,10);
                break;
            default:
                throw;
        }

    return temp;
}

teraz nie ma błędu. Dzięki.

komentarz 27 stycznia przez TOWaD Mądrala (6,000 p.)

@adrian17, Sorrki. Cofnąłem najlepszą, bo jednak nie rozwiązuje problemu (Może ktoś znajdzie wytłumaczenie). Porostu nie użyłem realloc (case add) i nie było błędu.

free(): double free detected in tcache 2

Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (no_tid=0, signo=6, threadid=140737348183872) at ./nptl/pthread_kill.c:44
44      ./nptl/pthread_kill.c: No such file or directory.
(gdb)

Jednak czeka mnie głębsze grzebanie w źródłach jak będę chciał to skończyć. A miało być to tylko parę godzin. A jak sumowca to z 40h będzie i jeszcze nic, No nic fajnie stracony czas.

 

komentarz 27 stycznia przez adrian17 Ekspert (345,160 p.)

...?

Ale wszystko co wspomniałem to prawdziwe istniejące problemy.

nie użyłem realloc (case add) 

Nie wiem co znaczy "case add" jak realloc() wołałeś z odejmowania, ale no... dosłownie tylko zamaskowałeś objaw.

Wystarczy że w Twoim kodzie napiszę zwykłe

int main() {
    try {
        bignum a("345");
        bignum b = a;

I już mam double free.

komentarz 27 stycznia przez TOWaD Mądrala (6,000 p.)
edycja 27 stycznia przez TOWaD

OK.

Ale nie rozwiązuje problemu z kasowaniem  zbędnie zajmowanej pamięci, po odejmowaniu.

Nie mówię ze to zła odpowiedz, bardzo dobra tylko, akurat to nie rozwiąże problemu realloc tak myślę. Może jednak globalna funkcja "czy cóś".

tu 200 znaków tablica , a potrzebuję 1 lub 2, [online]

 o(bignum(std::string(200,'2')-bignum(std::string(200,'1'))));  //edit
bignum(std::string(200,'2')-bignum(std::string(200,'1')))=(rozmiar Tablicy 200) 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111  //edit

PS.

Ale to następny problem. (= chciałem zakombinować z std::string bn= ???, ale to w fazie pomysłu lub zamiast tego przeciążyć operator char, ale za to, się nie babrałem, więc na razie nie wiem o czym mówię tylko luźny pomysł. )

Edit: sorki chodziło mi o

o(bignum(std::string(200,'2')-bignum(std::string(200,'2'))));
bignum(std::string(200,'2')-bignum(std::string(200,'2')))=(rozmiar Tablicy 1) -0 // a rzeczywisty 200

 

komentarz 27 stycznia przez adrian17 Ekspert (345,160 p.)

No, realloc() jest po prostu zły.

old=newone;

Ta linia nic nie robi, bo `old` to tylko argument funkcji - zgaduję że chciałeś zmieniać pole ze wskaźnikiem...? Ale jak tak, to w ogóle nie rozumiem czemu metoda realloc bierze argument wskaźnikowy.

komentarz 27 stycznia przez TOWaD Mądrala (6,000 p.)
edycja 27 stycznia przez TOWaD

realloc bierze argument wskaźnikowy. 

Bo nie było konstruktora kopiującego. :). Tak by może była referencja.

 

void *realloc( void *ptr, size_t new_size );
	

[link], też wskaźnik.

old = newone // zmiana adresu wskaźnika, takie było zamierzenie. 
  delete [] old; // usuwam zajmowaną pamięć, nie wskaźnik.
    old=newone; // przypisuję nowo zarezerwowaną pamięć do starego wskaźnika
    newone=nullptr;  // zeruję tymczasowy wskaźnik, ale i tak bedzie usuniety.

 

komentarz 27 stycznia przez j23 Mędrzec (194,920 p.)

Ten realloc to raczej jakoś tak powinien wyglądać:

void bignum::realloc(char * &old, const size_t newsize) 
{
    char* newone = new char[newsize + 1] {};
    std::copy_n(old, std::min(size, newsize), newone);
    delete [] old;
    old = newone;
}

W sumie w przypadku tablic char[] możesz użyć standardowej funkcji realloc z C. Choć w przypadku C++ lepiej użyć std::vector.

komentarz 27 stycznia przez adrian17 Ekspert (345,160 p.)

Wciąż, trwa pytanie do czego ma być argument `old` - skoro to jest tylko wołane postacią

temp.realloc(temp.ptrlgnr,10);

, to czemu nie po prostu wyrzucić ten argument i

ptrlgnr = newone;

(BTW, ten realloc wygląda zupełnie jak coś co w stdlibie nazywa się shrink_to_fit - no i też nie wiem po co ten argument 10, jeśli zgaduję że możesz po prostu pomniejszyć do `size`?)

komentarz 27 stycznia przez j23 Mędrzec (194,920 p.)

Wciąż, trwa pytanie do czego ma być argument `old` - skoro to jest tylko wołane postacią

To jest tak zwane C z klasami :P

komentarz 27 stycznia przez TOWaD Mądrala (6,000 p.)

@j23, 

Bo próbowałem to zadanie zrobić. Zadanie C++. A tu

Nie dozwolone jest używanie niczego spoza biblioteki iostream

Tez zdecydowanie wolę STL, a wolał bym woleć Boost, ale się nie nauczyłem :). 


void bignum::realloc(char * &old, const size_t newsize)

Ale coś jeszcze nie działa. Może jutro dokładniej nad tym siądę. 


Myślałem że blisko https://forum.pasja-informatyki.pl/446633/referencja-do-wskaznika-jak-to-dziala

Ale napisałem funkcję dla testu [online]

#include <iostream>

using namespace std;
#include <iostream>

void
realloc (char *old, const size_t &newsize)
{

  char *newone = nullptr;
  newone = new char[newsize + 1] {};
  {
    int i = 0;
  for (const auto & x:"Hi")
      newone[i++] = x;
  }
cout<<newone<<endl;
 /* for (size_t i = 0; i < newsize; i++)
    newone[i] = old[i];
*/
  delete[]old;
  old = newone;
  newone = nullptr;
  return;

}


int
main ()
{

    char* p = new char[20]{};
    {int i=0;
    for(const auto& x:"Hallo word") p[i++]=x;
}
cout<<"old="<<p<<endl;
realloc (p, 3);
cout<<"new="<<p<<endl;


  return 0;
}

A tu zonk:

old=Hallo word
Hi
new=jUUU

 

komentarz 27 stycznia przez adrian17 Ekspert (345,160 p.)

Ale coś jeszcze nie działa

...ten nowy kod na oko ma jeszcze mniej sensu.

ptr->ptrlgnr[i]=ptrbigger.ptrlgnr[i];//przepisujemy pozostałe liczby

`ptr` jest zawsze nullem w tym miejscu.

W ogóle to tego też nie rozumiem:

void bignum::subtract(const bignum & ptrbigger,const bignum &ptrlower, bignum* ptr) {

Czemu to ma... aż trzy parametry? Po co w ogóle ten wskaźnik?

Czemu nie robisz dokładnie tego co biblioteka standardowa normalnie robi, czyli

bignum operator-(const bignum& lhs, const bignum& rhs); // nie metoda
// albo
bignum bignum::operator-(const bignum& rhs);

Tutaj w ogóle nie powinno być żadnych referencji do wskaźnika, ani w ogóle żadnych wskaźników w argumentach, bo po co...?

Ale napisałem funkcję dla testu [online]

Ale co, że zonk? Ten kod ma ten sam błąd co wcześniej, próbujesz używać zwolnioną pamięć.

old=Hallo word

Hi

new=jUUU

Mi na to AddressSanitizer od razu krzyczy:

==1736==ERROR: AddressSanitizer: heap-use-after-free
    (...)
    main /home/adrian/test/main.cpp:39

 

komentarz 28 stycznia przez TOWaD Mądrala (6,000 p.)

ten nowy kod na oko ma jeszcze mniej sensu.

Tak tak ten wskaźnik nie potrzebny, koncepcja się zmieniła i nie poprawiona.

To stary tylko niepoprawiony. Dziś wieczorem posprzątam zostawię to co tylko potrzebne.

Ale co, że zonk? Ten kod ma ten sam błąd co wcześniej, próbujesz używać zwolnioną pamięć.

W main() działa coś takiego

#include <iostream>

using namespace std;

int main()
{
    int * old = new int [10]{1};
    for(int i=0;i<10;i++) old[i]=i;
    for(int i=0;i<10;i++) cout<<old[i]<<' ';
    cout << "<-main" << endl;
    delete []old;

    int * newone = new int [20]{1};

    old=newone;

    for(int i=0;i<20;i++) old[i]=i*2;
    for(int i=0;i<20;i++) cout<<old[i]<<' ';
    cout << "<-main!" << endl;
    delete [] old;
    
return 0;
}

i trochę nie mogę zatrybić, czemu w funkcji nie działa. OK newone jest zmienną automatyczną, ale to co wykazuje już nie, dlatego przestawiam wskaźnik old na newone, a newone może zostać zniszczone. I jak bym przekazał wskaźnik jako referencję to nie zrobił by mi kopi tego wskaźnika i nie wywalało by błędu,

komentarz 28 stycznia przez TOWaD Mądrala (6,000 p.)

ogarnięta  ta funkcja [online] i stacoverflow przykład.


#include <iostream>

using namespace std;
void realloc1(int**data,const int size);
int main()
{
    int * old = new int [10]{1};
    for(int i=0;i<10;i++) old[i]=i;
    for(int i=0;i<10;i++) cout<<old[i]<<' ';
    cout << "<-main" << endl;
    delete []old;

    int * newone = new int [20]{1};

    old=newone;
    for(int i=0;i<20;i++) old[i]=i*2;
    for(int i=0;i<20;i++) cout<<old[i]<<' ';
    cout << "<-main!" << endl;
    
    realloc1(&old,15);
    for(int i=0;i<15;i++) cout<<old[i]<<' ';
    cout << "<-main realoc1!" << endl;
    delete [] old;
    
return 0;
}

void realloc1(int**data,const int size)
{
    delete []*data ;
    int * newone = new int [size]{};
    for(int i=0;i<size;i++) newone[i]=i*3;
    *data=newone;
}

 

komentarz 28 stycznia przez j23 Mędrzec (194,920 p.)

Dobra, tak to powinno wyglądać, bo widać, że masz jakiś dziwny problem z tym:

bignum::bignum(const std::string& longnum)
    :ptrlgnr{nullptr}, size{0} 
{
    ...
    realloc(longnum.size()); // do pierwszej (i kolejnych) alokacji używasz tej funkcji, a nie 'gołego' new
    ...
}

bignum::~bignum() 
{
    delete[] ptrlgnr;
}

void bignum::realloc(size_t newsize) 
{
    if (newsize == size) return;
    char* newone = new char[newsize];
    std::copy_n(ptrlgnr, std::min(size, newsize), newone);
    delete [] ptrlgnr;
    ptrlgnr = newone;
}

 

komentarz 28 stycznia przez TOWaD Mądrala (6,000 p.)

Dzięki Wam. Działa jak należy. Wracam najlepszą, bo w końcu rozwiązałem problem.

Jak jeszcze dostosuję konstruktory to link do całego kodu.

@j23, Faktycznie jakaś chwilowa zaćma. Raz na pół roku malutki projekcik, to zdecydowanie z mało, by utrzymać formę.

bignum::bignum(const std::string& longnum)
    :ptrlgnr{nullptr}, size{0} 

Bardziej coś takiego, ale to (new char[longnum.size()+1]) może się nie powieść i dobrze by było się na przygotować.

bignum::bignum(const std::string& longnum)
    :ptrlgnr{new char[longnum.size()+1]{}}, size{longnum.size()} {};

A co do funkcji to zastosowałem to:

void bignum::shrinftofit(){
        if(!ptrlgnr)
        throw std::bad_alloc();
    char* newone=nullptr;
    newone=new char[size+1] {}; // +1 zarezerwowany dla znaku '\0'
    newone[size]=0;
    if(newone)
        for(size_t i=0; i<size; i++)
            newone[i]= ptrlgnr[i];
    else
        throw std::bad_alloc(); // jeżeli nie udała się rezerwacja pamięci.
    delete [] ptrlgnr;
    ptrlgnr=newone;
    newone=nullptr;
    return;
}

No przecież po to się stosuje prywatne funkcje by nie podawać argumentów :).

komentarz 28 stycznia przez j23 Mędrzec (194,920 p.)
newone=new char[size+1] {}; // +1 zarezerwowany dla znaku '\0'
newone[size]=0;
if(newone)
    for(size_t i=0; i<size; i++)
        newone[i]= ptrlgnr[i];
else
    throw std::bad_alloc(); // jeżeli nie udał

Ta część kodu ma parę bezsensów: alokujesz, ustawiasz zero na końcu, później sprawdzasz, czy alokacja się powiodła. Po pierwsze, new domyślnie w razie niepowodzenia rzuca wyjątek std::bad_alloc, więc do sprawdzenia warunku nie dojdzie - zatem jest bez sensu. Nawet gdyby założyć, że new zwróci nullptr, to akcja z przypisaniem zera na końcu wywróci program błędem nieprawidłowego dostępu do pamięci - i znowu: sens tego warunku jest żaden.

Coś takiego wystarczy:

char* newone = new char[size + 1]; 
newone[size] = 0;
for(size_t i = 0; i < size; i++)
    newone[i] = ptrlgnr[i];

Tak poza tym nie widzę sensu tej funkcji. Ona, jeśli dobrze rozumiem, powinna przyciąć pamięć do niezbędnego minimum, a tutaj jest tylko realokacja pamięci, czyli blok pamięci przenosisz w inne miejsce - zysk z tego żaden.

komentarz 28 stycznia przez TOWaD Mądrala (6,000 p.)

Ta część kodu ma parę bezsensów...

Śliczne dzięki za merytoryczne uwagi i poświęcony czas.

Czy można złapać błąd nieprawidłowego dostępu do pamięci?

Tak poza tym nie widzę sensu tej funkcji.

Ma i to wielki

...subtract(const bignum & ptrbigger,const bignum &ptrlower) {

    while(!ptrlgnr[size-1]) // powtarzaj dopóki są zera wiodące
        if(size>1)
            size--; //jeżeli 0 wiodące
        else
            break;
shrinftofit();
    return;
    
}
/// czyli 2222 - 2222 = 0000 => shrinktofit() zamiast 0000 jest 0;
/// bignum( string(1024,'2'))-bignum( string(1024,'2'))= 1k bajtów, a po shringtofit() tylko 1 bajt

 

komentarz 28 stycznia przez j23 Mędrzec (194,920 p.)
edycja 28 stycznia przez j23

Czy można złapać błąd nieprawidłowego dostępu do pamięci?

W bloku try...catch tego wyjątku nie złapiesz, bo to wyjątek niskopoziomowy (jeśli się nie mylę, rzucony przez CPU i obsłużony przez system). Zresztą ten wyjątek nie powinien wystąpić w poprawnie napisanej aplikacji.

Ma i to wielki

Przy takim użyciu to oczywiście tak - zmieniasz wartość size, więc taka realokacja ma sens.

komentarz 28 stycznia przez adrian17 Ekspert (345,160 p.)

Czy można złapać błąd nieprawidłowego dostępu do pamięci?

Od tego zacząłem cały wątek - użyłem AddressSanitizera ;)

komentarz 29 stycznia przez TOWaD Mądrala (6,000 p.)

Jednak, ale będę szukał może to inny.

 ...} catch(std::exception & e) {
        std::cout<<e.what()<<std::endl;
        exit(-3);
    } 
...
} catch(...) {
        exit(-6);
    }
..
//////////////////////
//jednak nie łapie exception::bad_alloc(), bo przy alokacji powinen złapać błąd.
/*
size=7274160wskaznik =☻☺        ♦
sign=+, correct=1

Process returned -1073741819 (0xC0000005)   execution time : 1.792 s
Press any key to continue.
*/

/*
Po dołaczeniu //#include <algorithm> pewnie makro #define n(x), więc copy(begin,end,destination) odpada.
||=== Build failed: 50 error(s), 0 warning(s) (0 minute(s), 5 second(s)) ===|
*/

 

komentarz 29 stycznia przez j23 Mędrzec (194,920 p.)

jednak nie łapie exception::bad_alloc()

A ile pamięci alokujesz? 7274160? Przecież to tylko 7MB...

komentarz 29 stycznia przez adrian17 Ekspert (345,160 p.)
Też zupełnie nie rozumiem co TOWaD w tym ostatnim bloku kodu wrzucił.
komentarz 29 stycznia przez TOWaD Mądrala (6,000 p.)

To chyba jednak kompilator. Online kończy się bez błędu. 

main.cpp
....
(b+c).print();
...
/* Ale i tu wynik nie oczekiwany ----------------
/* w domowym rzuca błędem.
size=4wskaznik =
sign=+, correct=1
0*/
/*
ale 
...Program finished with exit code 0
Press ENTER to exit console.
*/

A ile pamięci alokujesz? 7274160? Przecież to tylko 7MB...

Nie jak dodałem posta to pomyślałem, że to nie to.

VS community, lub Qt jest chyba nie nieuniknione :). To jest z porządnym debuggerem.

Też zupełnie nie rozumiem co TOWaD w tym ostatnim bloku kodu wrzucił.

/*1*/ catch(std::exception & e) // powinno złapać bad_alloc() to oczywiste to wiesz, bardziej dla innych forumowiczów 
/*2*/ // ||=== Build failed: 50 error(s), 0 warning(s) (0 minute(s), 5 second(s)) ===| to podłączeniu <algorthm>
/*3*/ (b+c).print() /*online ----------------
size=4wskaznik =
sign=+, correct=1
0*/
/* a na moim kompilatorze
size=7274160wskaznik =☻☺        ♦
sign=+, correct=1
*/

 

komentarz 29 stycznia przez adrian17 Ekspert (345,160 p.)
Pewnie się sypie, bo w konstruktorze kopiującym nie ustawiasz `size`, więc dzieje się nonsens.

Natomiast to co wklejasz to wciąż zupełnie losowe zbitki kodu bez kontekstu - poważnie, nikt poza Tobą tego nie rozczyta.
komentarz 29 stycznia przez adrian17 Ekspert (345,160 p.)
I tak jak mówił j23, ten `if (!wsk) throw bad_alloc();` to masło maślane - operator `new` już to robi za Ciebie.
komentarz 29 stycznia przez TOWaD Mądrala (6,000 p.)
edycja 30 stycznia przez TOWaD

@adrian17,  ok będę pamiętał, już nie chało mi się szukać(bo myślałem max parę godzin 4-5 mi to zajmie )i myślałem,że nie zaszkodzi.

nie ustawiasz `size`...

też to odkryłem, jak wyzerowałem size{} w konstuktorze

ps. ptr add(...,..., ptr) coś jednak robił, bo dodawanie działało :), a teraz działa dopiero po przebudowie..

nikt poza Tobą tego nie rozczyta

To fakt to może być rzeczywiście poważny problem. Test na informatyka zliczony na 0%. Aja jaj :).

Edit:: na polonistę też 0% :)

Ale trochę poprawione błędy [online], ale i tak nie działa *this=konstruktor przypisania coś nie działa ale tu już sam dojdę.

Ale gdzieś kiedyś czytałem że (const std::sting & ) to tak nie można, jak byście wiedzieli lub znali źródło

 

 

komentarz 4 lutego przez TOWaD Mądrala (6,000 p.)

[online], no jednak te c++ to trudna sprawa. Konstruktor kopiujący mi jednak nie działa.

raz ambiguous, raz typ np char [3] kompilatorowi się nie podoba :).

        n(" konstruktor kopiujacy char BigNum a=\"10\"");
          //  BigNum a="10";
          // o(a)
       }

 

komentarz 4 lutego przez adrian17 Ekspert (345,160 p.)
edycja 4 lutego przez adrian17
Jakby co, nazwa "konstruktor kopiujący" zazwyczaj odnosi się tylko do konstruktora klasy C który bierze na wejście C. Więc to co pokazujesz to nie jest konstruktor kopiujący.

Po drugie, no, bo nie możesz przeskoczyć przez stringa tylko musisz zrobić konstruktor biorący na argument const char*.

Po trzecie, wyrzuć te operatory przypisania z innymi typami. Do podstawowego działania, nie potrzebujesz przypisania inta, jak masz konstruktor biorący inta i operator przypisania na BigNum&.

Po czwarte, jeśli nie musisz, to nie rób na ślepo konstruktorów przenoszących bo robisz to mocno po omacku.
komentarz 5 lutego przez TOWaD Mądrala (6,000 p.)

0)//te przypisania to był taki wymysł na czas kompilacji, bo nie chało mi się pisać BigNum ..., ale pojawiło się parę fajnych problemów i dobrze by było to zrozumieć, by wiedza trafiła do pamięci stałej. 

1) Może nie jest, ale wygląda podobnie. A przede wszystkim C a=coś, normalnie uruchamia taki konstruktor, jeśli coś jest klasy C. Jak nie jest to jak się tak funkcja nazywa.

2) No właśnie const char * to wskaźnik, a wydawało mi się, że w funkcji, wskaźnik "zapomina" ile pamięci wskazuje.  Czyli trzeba zrobić tak, funkcja(int tab*, int size)?

C c =(ptr, size); a to nie to samo C coś="char".

Kombinowałem już C coś = ""; nawet się kompilował i nie zgłaszał błędów, ale wartość była zła. To jeszcze gorzej dlatego się zapytałem.

Natomiast ciekawe jest to, jak mi się wydaje kompilator dobrze wie ile pamięci jest zarezerwowanej const char [ile]. I delete [] też wie ile pamięci ma skasować.


w ogóle fajne by było : //taka dygresja tylko wiem ze to nie możliwe.

ptr = 123456789; /new

ptr2=ptr+6 // ptr2=789; a ptr skasować tylko 123456;


3) No spróbuje bez, ale teraz tak pomyślałem, że nie potrzebnie kasuję pamięć:

BigNum& BigNum::operator=(const int& num) {
    n("BigNum& BigNum::operator=(const int& num)")
   // delete [] ptrLgNr;  <- bo przecież nie mam jej zarezerwowanej ? Czy nie?
   // ptrLgNr =nullptr;
    std::string temp=std::to_string(num);
    size=temp.size();
    constuctor(temp);
    return *this;
}

,ale bez tego się nie kompiluje b="coś", a int, i owszem jest ok. Ale posiedzę jeszcze nad tym trochę może zrozumiem.

natomiast martwi mnie inna rzecz

BigNum a(BigNum("15"));

tu jest tylko raz uruchomiony destruktor.

4) Do tego mi jeszcze daleko, w ogóle się w to nie wgryzałem. Aczkolwiek czytałem coś takiego, jak dobrze zrozumiałem to c++11 wartości funkcji są przesuwane.

Ale linku nie podam bo oryginalny się nie otwiera "want speed pass by value c++next".

A wyszukiwarce pojawia się "Want speed? Don’t (always) pass by value."

komentarz 5 lutego przez j23 Mędrzec (194,920 p.)

2) No właśnie const char * to wskaźnik, a wydawało mi się, że w funkcji, wskaźnik "zapomina" ile pamięci wskazuje.  Czyli trzeba zrobić tak, funkcja(int tab*, int size)?

Jeśli wskaźnik char* wskazuje na jakiś c-string, to nie trzeba parametru size.

jak mi się wydaje kompilator dobrze wie ile pamięci jest zarezerwowanej const char [ile] I delete [] też wie ile pamięci ma skasować.

Kompilator nic nie wie, dlatego używasz new a nie zwykłej tablicy. Menedżer pamięci systemowej wie, ile dana alokacja zajęła pamięci. W przypadku gdy new[] alokuje tablicę typu klasowego, wtedy wielkość takiej tablicy jest zapisana na ujemnym offsecie, dzięki czemu delete[] "wie", ile destruktorów ma wywołać.

komentarz 5 lutego przez TOWaD Mądrala (6,000 p.)

A jak nie wskazuje c-string?  Czy to nie jest jakaś luka programu. Bo w któreś wersji program zrobił rekonesans po pamięci.

A dziękuje z info

Menedżer pamięci systemowej wie,

chodziło mi o to const char &

error: conversion from 'const char [3]' to 'BigNum' is ambiguous

Ze kompilator wie ile znaków c-stringa.

A po usunięciu operatorów przypisania i dodaniu konstruktora:

BigNum::BigNum(const char* num){
    constructor(std::string(num,num+sizeof(num)));
}

Process returned -107.......... jakaś duża liczba to chyba nie dobrze :). 

 

komentarz 5 lutego przez adrian17 Ekspert (345,160 p.)

Potężnie kombinujesz. sizeof() tutaj nie ma związku, daje rozmiar wskaźnika a nie tekstu. Konstruktor std::string sam sobie umie wyliczyć rozmiar tekstu.

(i co to jest `constructor()`...?)

Podobnie tutaj:

4) Do tego mi jeszcze daleko, w ogóle się w to nie wgryzałem. Aczkolwiek czytałem coś takiego, jak dobrze zrozumiałem to c++11 wartości funkcji są przesuwane.

Ale linku nie podam bo oryginalny się nie otwiera "want speed pass by value c++next".

A wyszukiwarce pojawia się "Want speed? Don’t (always) pass by value."

Najpierw ogarnij podstawy i napisz kod który się skleja i działa, a potem się zastanawiaj nad szybkością. Na razie zapomnij o && i przenoszeniu :/

komentarz 5 lutego przez TOWaD Mądrala (6,000 p.)

nie sprawdziłem  konstruktorów, rzeczywiście jest:

string (const char* s)

wcześniej dostałem, błąd kompilacji myślałem ze nie ma.

constructor(std::string) - poprawiona literówka w constuctor(std::string) prywatna funkcja, która robi to samo co konstruktor.

Najpierw ogarnij podstawy i napisz kod który się skleja i działa

No myślałem,  ze mam to za sobą, ale pierwsze i drugie do ogarnięcia.

"operator przypisania char a=\"-12\""

"BigNum& BigNum::operator=(const BigNum& rhs"

Program received signal SIGSEGV, Segmentation fault.
0x0000555555558046 in BigNum::operator= (this=0x7fffffffeb20, rhs=...) at bignum.cpp:113
113             ptrLgNr[i]=rhs.ptrLgNr[i];
(gdb) Quit

https://onlinegdb.com/5RYw9sMoc

Się zawziąłem by skończyć, a tu ten kod robi mi psikusy jak szarlotka z "Jabłka Adama".

komentarz 5 lutego przez adrian17 Ekspert (345,160 p.)

prywatna funkcja, która robi to samo co konstruktor.

Domyślam się, tylko... po co, skoro jest konstruktor?

Mi tam Twój kod się sypie znacznie wcześniej, w `BigNum("15")`, bo alokujesz 0 znaków w `constructor()` i próbujesz do nich pisać.

Poważnie, zacznij to odpalać z jakimś analizatorem zamiast na ślepo liczyć na segfaulty - bo teraz to robisz ze mnie i j23 chodzącego AddressSanitizera.

BTW, `case '0' ... '9':` nie jest w standardzie języka.

komentarz 6 lutego przez TOWaD Mądrala (6,000 p.)
edycja 6 lutego przez TOWaD

po co, skoro jest konstruktor?

Też tak kombinowałem, ale nie mogłem uruchomić konstruktora w innych konstruktorach.

Jeszcze raz intro, to miał być zabawa na 24h czyli gdzieś na 24 dni po godzince. Najwyżej bym przegapił 24 odcinki  "M jak miłość". Ale przy okazji jak by się dało wcześniej to może bym komuś pomógł, a na pewno nie zaszkodził(tj miejmy nadzieję ).

I dlatego ten nieszczęsny constructor(...), zamiast klepać kod "na miarę" dla każdego konstruktora to jeden kod/bubel dla wszystkich

        BigNum(const int& num);
        BigNum(const char* num); 
        BigNum& operator=(const int& num);
        BigNum& operator=(std::string num);
// i nawet 
       BigNum(const std::string& longNum = "0"){constructor(longNum);}

A że maił być szybkie zadanie, to tego typu udoskonalenia. To tak jak w dowcipie o regex "...teraz mam już dwa problemy".


bo teraz to robisz ze mnie i j23 chodzącego AddressSanitizera.

Sokki bardzo, jeszcze raz dzięki za pomoc.

Ja jak się na coś uwezmę, to ... na pewno nie skoczę. A jak coś sobie pokpię... to rezultat bywa amazing, cokolwek to znaczy.

komentarz 6 lutego przez j23 Mędrzec (194,920 p.)
BigNum::BigNum(const BigNum && other) { /*:size{other.size}*/
    // if(ptrLgNr) delete [] ptrLgNr;
        n("BigNum::BigNum(const BigNum && other)")

    //ptrLgNr=nullptr;
    if(other.size) {
        ptrLgNr=new char[other.size+1] {};
        size=other.size;
        for(size_t i; i<size ; i++) {
            ptrLgNr[i]=other.ptrLgNr[i];
        }
        // memcpy(ptrLgNr,other.ptrLgNr,other.size);
    } else
        throw ErrDim();
}

Implementacja tego konstruktora jest bez sensu. Tak może być:

void BigNum::swap(BigNum & other) // dodaj jako prywatną metodę
{ 
    std::swap(size, other.size);
    std::swap(ptrLgNr, other.ptrLgNr);
    std::swap(capacity, other.capacity);
    std::swap(sign, other.sign);
    std::swap(correct, other.correct);
}


BigNum::BigNum(BigNum && other) 
    : BigNum()
{ 
    n("BigNum::BigNum(BigNum && other)")

    swap(other);
}

/* 
   wywal:
        BigNum& operator=(const int& num); 
        BigNum& operator=(std::string num); 
   i inne operatory przypisania/przenoszenia, zostaw to:
*/

BigNum& operator= (BigNum num)
{
    swap(num);
    return *this;
}

 

komentarz 6 lutego przez adrian17 Ekspert (345,160 p.)

Implementacja tego konstruktora jest bez sensu. Tak może być:

j23, podtrzymuję moją rekomendację że póki nie wie co robi, to prościej w ogóle nie kombinować z przenoszeniem.

Też tak kombinowałem, ale nie mogłem uruchomić konstruktora w innych konstruktorach.

Możesz.

BigNum(const char *p) : BigNum(std::string(p)) {}

 

komentarz 6 lutego przez j23 Mędrzec (194,920 p.)
Z drugiej strony skoro już ma tam jakąś implementację konstruktora przenoszącego, to niech chociaż zobaczy, jak to powinno poprawnie wyglądać. Jeśli uzna, że to go przerasta, to przecież nie musi tego używać. Zawsze może spytać, dlaczego tak a nie inaczej.
komentarz 7 lutego przez TOWaD Mądrala (6,000 p.)
edycja 7 lutego przez TOWaD

że to go przerasta,

Jeden nie udany projekcik i żarty sobie stroicie.

Mniej  więcej  wiem, jak powinien wyglądać Opus magnum, strona 1031. Tu się pojawił przenoszący tylko by zobaczyć kiedy się uruchamia.

BigNum(const char *p) : BigNum(std::string(p)) {}

Dzięki, ale chyba jednak wolę swój void. Edit:: I żeby nie było że, nic nie wiem o dziedziczeniu konstruktora. Po prostu za mało używam C++.

Edit:: Wielkie dzięki za -fsanitize=address, aczkolwiek nie udał mi się zainstalować tego na c::b jeszcze.

 

komentarz 8 lutego przez TOWaD Mądrala (6,000 p.)

AddressSanitizer, a tak się cieszyłem. A tu trzeci problem

kompilator wersja plik rename.txt

REQUIRED BASE:
 * gcc-core (gcc-5.1.0-tdm-1-core)
 * binutils (binutils-2.24-1-mingw32-bin)

strona HOWTO: Use Address Sanitizer

Address Sanitizer is a tool developed by Google detect memory access error such as use-after-free and memory leaks. It is built into GCC versions >= 4.8 and can be used on both C and C++ codes.

czyli na moje oko gcc-5.1.0 >= 4.8,

wywołanie programu:


Executing: ..Program Files (x86)\CodeBlocks/cb_console_runner.exe ..noleak\bin\Debug\noleak.exe" -fsanitize=address -static-libasan -g (in ..\noleak\noleak\.)

dla programu

#include <iostream>
#include <cstring>

int main(int argc, const char *argv[]) {
    char *cstr = new char[50];
    strcpy(cstr, "Hello World");
    std::cout << cstr << std::endl;

    delete cstr;
    return 0;
}

konsola

Hello World

Process returned 0 (0x0)   execution time : 0.082 s
Press any key to continue.

żadnego dodatkowego komunikatu.

komentarz 8 lutego przez adrian17 Ekspert (345,160 p.)
edycja 8 lutego przez adrian17
A, no pewnie windowsowy port GCCa nie wspiera asana :P To potraktuj to jako uwagę na przyszłość.
komentarz 8 lutego przez TOWaD Mądrala (6,000 p.)
Czyli zamiana mingw na g++ nic nie zmieni?

A z konsoli Windows będzie to samo?
komentarz 8 lutego przez adrian17 Ekspert (345,160 p.)

Twój g++ to jest mingw. mingw to dosłownie port gcc/g++ na windowsy.

A z konsoli Windows będzie to samo?

Konsola nic nie zmienia. Z tego co wiem, na windowsie wsparcie sanitizera mają clang i oczywiście Visual Studio.

komentarz 8 lutego przez TOWaD Mądrala (6,000 p.)

zobaczymy i clangem

Ale i konsoli w ogóle nie che pójść

'g++' is not recognized as an internal or external command,

  Jestem  w katalogu projektu z plikiem main.cpp, a zmienna środowiskowa dodana w ten sposób

komentarz 8 lutego przez adrian17 Ekspert (345,160 p.)
Chyba już za bardzo odjeżdżasz. Po pierwsze, to naprawdę odjechało od oryginalnego pytanie. Po drugie, nawet gdybym chciał pomóc, to dałeś praktycznie 0 informacji o tym co zrobiłeś, co gdzie jest, jaki jest PATH.
komentarz 8 lutego przez TOWaD Mądrala (6,000 p.)
edycja 8 lutego przez TOWaD
Edit:: Myślę, że ścieżki pomylone. Jutro sprawdzę.

Sorki ze obrazki usunąłem, ale wiele nie wnosiły.
komentarz 8 lutego przez j23 Mędrzec (194,920 p.)

Do ścieżki PATH powinieneś dodać ścieżkę do folderu <MinGW>\bin.

Jeśli mnie pamięć nie myli, addres sanitizer nie był przeportowany na Windowsa, ale może coś się zmieniło... Próbowałbym z MSYS2 lub nawet WSL.

komentarz 8 lutego przez adrian17 Ekspert (345,160 p.)

Jeśli mnie pamięć nie myli, addres sanitizer nie był przeportowany na Windowsa

Słyszałem że ma go Clang, no i jest dostępny z Visual Studio (nie wiem czy nie trzeba go zaznaczyć w instalatorze).

komentarz 10 lutego przez TOWaD Mądrala (6,000 p.)

@j23, 

folderu <MinGW>\bin.

Się kapłonem między innymi edytowałem posta. Ale  i tak brakowało jakieś libki może linkera czy cóś, akurat nie ważne.

WSL - no chciałbym ale odkładam na razie.

komentarz 10 lutego przez TOWaD Mądrala (6,000 p.)

VS - trochę chyba ciężkie jak na mój komp. Będzie wszystko mulić, ale nie wiem może się skuszę. Miałem wcześniej z miesiąc, ale skończyło się formatem. Zapewne za dużo niepotrzebnych rzeczy po instalowałem. A może już komp tylko na Linuksa się nadaje.

Na razie chciałbym podpytać czy coś wybrać z tego -> link , wybrane stąd. Oczywiście  chciałbym, na pewno spróbować tego, przez sentyment do Turbo Pascala.

Jak dorwę jakąś fajną książkę, to nauczę się wsl i github.

komentarz 10 lutego przez j23 Mędrzec (194,920 p.)

Oczywiście  chciałbym, na pewno spróbować tego

Przecież kompilator C++ Buildera to port clanga dostosowany do potrzeb VCL-a. Jeśli nie potrzebujesz niestandardowych rozszerzeń, to instaluj po prostu clanga.

Jak dorwę jakąś fajną książkę, to nauczę się wsl i github.

A to do tego trzeba książek? Współczesny WSL to wirtualka Linuksa w Windowsie (wcześniej warstwa zgodności, coś jak WINE).

komentarz 10 lutego przez TOWaD Mądrala (6,000 p.)

A to do tego trzeba książek?

Nie trzeba,bo bez internetu się nie obędzie, ale lubię. A przy okazji uporządkowana wiedza.

komentarz 11 lutego przez TOWaD Mądrala (6,000 p.)

@TOWaD, 

na pewno spróbować tego,

No się nie udało, nie da się odpalić zwykłej konsoli.

pewnie przez błąd

Nie mówiąc że, nie można było wybrać ścieżki instalacji by C: nie zaśmiecać.

A co do

coś wybrać z tego -> link ,

Defender się burzy, że nieznany wydawca.

1
komentarz 11 lutego przez j23 Mędrzec (194,920 p.)
A niech się burzy...

Zainstaluj MSYS2, zainstaluj w nim kompilatory i inne rzeczy, które będą Ci potrzebne, i tam działaj.
1
komentarz 11 lutego przez adrian17 Ekspert (345,160 p.)
edycja 11 lutego przez adrian17
Coraz bardziej kombinujecie :P Nie wiem co powiedzieć. VS działa praktycznie out of the box, dowolny kompilator na linuxie działa out of the box, clang na windowsie... nie próbowałem, ale nie zdziwię się jeśli też ładnie działa. W dodatku teraz (od lat) możesz na windowsie zainstalować ze Sklepu i odpalić WSLa który jest praktycznie pełnym wirtualizowanym linuxem wbudowanym w Windowsa i na nim odpalić gcc czy co chcesz*. Tymczasem Wy się bawicie z Builderem (który pierwszy raz w życiu widzę by ktoś z własnej woli instalował), albo z msys2 który jest frankensteinową atrapą userspace'a linuxowego (która może i działa, ale no... są zdecydowanie prostsze sposoby. EDIT: plus, msys2 też po prostu zawiera mingw, więc... nie widzę różnicy, tak samo asan nie zadziała).

Przepraszam za ostre słowa, ale już nie wiem co tutaj się dzieje jak ja na kilka różnych współczesnych sposobów mogę łatwiutko odpalić Twój kod z instrumentacją, a Ty coraz bardziej kombinujesz pod górkę :(

*A, no i jeszcze najprostszy ad-hoc sposób: dosłownie wkleić kod na https://godbolt.org/ i zobaczyć jak tam zadziała.
1
komentarz 11 lutego przez j23 Mędrzec (194,920 p.)
Nie kombinujecie, tylko OP kombinuje ;) VS jest za ciężki na jego komputer, kompilator C++ Buildera odradziłem mu, bo to port clanga, WSL sam mu zaproponowałem, a MSYS2 ma tę zaletę, że ma sporo bibliotek, które można sobie w prosty sposób zainstalować.

No i tak prawdę mówiąc, takie małe projekty można spokojnie pisać bez adres sanitizera, wystarczy być uważnym.
komentarz 11 lutego przez TOWaD Mądrala (6,000 p.)
Nie kombinuję, tylko sprawdzam opcje. I na tą chwilę rozczarowany jestem Embarcadero, bo mi po opisie wydało się, że będzie ok.

Clang chyba nie ma lib++ czy libstd++ lub czegoś tam i znowu będzie zonk.

A te dwie( MSYS2, WSL) opcję sobie wypróbuje. Mimo, że nie rozwiąże problemu.

Mogę spróbować z godbolt, ale nie jest intuicyjny. Wiec go unikałem.

A co do projektu wystarczy, kopiuj wklej z innych stron internetowych i będzie działał i bez myślenia. Ale nie o to chodzi, chodzi przecież jak najwięcej się nauczyć nie prawda?
komentarz 14 lutego przez TOWaD Mądrala (6,000 p.)
edycja 14 lutego przez TOWaD

Na VS działa(ale z prędkością kompa i z obsługą marna sprawa, nie wiem gdzie dodawać argumenty kompilacji.) i online na onlinegdb. (tj konstruktory działają).

Się pozbyłem BigNum (const sting & longNum) i wszystko pięknie dało się poustawiać.

To zawsze był strzał w stopę. (const <STL contener> & ref), a to, zawsze było ok  (iterator begin, iterator end), ale tu zrobiłem kopię, skoro kopie w c++11 nie są takie złe.

Na godbolt nie działa, a link do skopiowania strona notatnika lub error.

Piątkę zrobiłem z książki, ale cppreference jest fajna.

edit:

noexcept

zapomiałem.

komentarz 14 lutego przez adrian17 Ekspert (345,160 p.)
edycja 14 lutego przez adrian17

nie wiem gdzie dodawać argumenty kompilacji

W konfiguracji projektu masz checkboxy, na przykład: https://learn.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170#ide-msbuild

To zawsze był strzał w stopę. (const <STL contener> & ref), a to, zawsze było ok  (iterator begin, iterator end), ale tu zrobiłem kopię, skoro kopie w c++11 nie są takie złe.

Trudno powiedzieć co tu mówisz i większość brzmi... źle. Szczególnie nie brzmi jakby akurat kopiowanie stringa miało związek z Twoimi problemami, a kopie praktycznie zawsze są niewydajne; C++11 daje tylko więcej narzędzi do ich unikania.

Na godbolt nie działa

Patrząc na screenshota, widzę co najmniej kilka dziwnych rzeczy. -static-libasan, MinGW executor...? Masz dodaną jakąś bibliotekę tam?  Bo ja tylko wkleiłem kod, dodałem -fsanitize=address i tyle: https://godbolt.org/z/nsMM96nra . To jest narzędzie do szybkiego testowania, nie IDE ;D

 

 

 

 

komentarz 14 lutego przez TOWaD Mądrala (6,000 p.)

W konfiguracji projektu masz checkboxy

Zrobione (niestety polski gdzieś przegapiłem opcję w instalacji), ale nic nie dodało na końcu kodu.


Patrząc na screenshota, widzę co najmniej kilka dziwnych rzeczy. -static-libasan

static-libasan  - to chyba było w poradniku nie ważne.

Problem pewnie dotyczy braku cmake (pliku?/katalogu?). Bo nie chciało mi się przyklejać kodu i dodałem plik .zip do kompilatora templates>cmake>project>przeglądaj...

Może jakoś da się, cały projekt dodać.


Trudno powiedzieć ...

STL jednak w większości funkcji używa iteratorów np transform, copy itd, nie referencji

https://en.cppreference.com/w/cpp/algorithm/transform

std::transform
 
C++
Algorithm library
 
Defined in header <algorithm>
		
	(1) 	
template< class InputIt, class OutputIt, class UnaryOperation >

OutputIt transform( InputIt first1, InputIt last1,
                    OutputIt d_first, UnaryOperation unary_op );
...

 

 

komentarz 14 lutego przez adrian17 Ekspert (345,160 p.)

ale nic nie dodało na końcu kodu.

Na oko u mnie działa:

STL jednak w większości funkcji używa iteratorów np transform, copy itd, nie referencji

Bo są uniwersalnym mechanizmem iteracji. To nie znaczy że referencje do rzeczy są "strzałem w stopę", szczególnie w kodzie który ma zero związku z iteracją.

komentarz 14 lutego przez TOWaD Mądrala (6,000 p.)

t

Tak to działa i nawet błąd zgłasza głównym oknie programu.

==9052==ERROR: AddressSanitizer: heap-buffer-overflow on address

szczególnie w kodzie który ma zero związku z iteracją

Konstruktor tylko robi iterację, cała klasa w paru liniach tylko nie można by było tu zrobić operatora + i -; trzeba by było używać funkcji. A walidację dało by się zrobić w lambdach.

#include <iostream>
#include <algorithm>
#include <iterator>

int main()
{
    std::string normal("123");
    std::string BigNum;
    std::transform(normal.rbegin(), normal.rend(),
                    std::back_inserter(BigNum), 
                   [](unsigned char c) { return c-'0';});
    std::transform(BigNum.rbegin(), BigNum.rend(),
                     std::ostream_iterator<short>(std::cout, " "), 
                   [](unsigned char c) { return c;});
    std::cout<<std::endl;
    return 0;
}

strzałem w stopę

Osobiste doświadczenie. Po prostu nie do końca rozumiem referencję do kontenerów STL.

Nie raz mi referencja do kontenerów krwi napsuła, a już na pewno do stringa.

komentarz 14 lutego przez TOWaD Mądrala (6,000 p.)

@adrian17, Nawet za to jeszcze nie podziękowałem. Dzięki, dawno się tyle rzeczy nie dowiedziałem i to w dyskusji to nie to samo co przeczytać. Dużo bardziej zapada w pamięć.

Podobne pytania

0 głosów
1 odpowiedź 148 wizyt
pytanie zadane 30 marca 2020 w C i C++ przez Quegon23 Nowicjusz (150 p.)
0 głosów
2 odpowiedzi 316 wizyt
pytanie zadane 16 lutego 2019 w C i C++ przez niedzwiedz89 Nowicjusz (150 p.)
+2 głosów
2 odpowiedzi 603 wizyt
pytanie zadane 3 kwietnia 2017 w C i C++ przez Evelek Nałogowiec (28,960 p.)

92,620 zapytań

141,474 odpowiedzi

319,813 komentarzy

62,003 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...