Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

C++ Tablica dynamiczna wysypuje się przy dodawaniu stringów do tablicy.

Ostatnio zmodyfikowano 2019-11-07 17:56
Autor Wiadomość
greenbanzai
Temat założony przez niniejszego użytkownika
C++ Tablica dynamiczna wysypuje się przy dodawaniu stringów do tablicy.
» 2019-11-06 22:48:50
Cześć! Kiedy ustawiam, że moja tablica dynamiczna ma przechowywać obiekty typu string i w pętli for dodaję kolejne elementy i przychodzi czas na utworzenie nowej tablicy o większej pojemności (u mnie w kodzie capacity) to program zgłasza wyjątek:"Zgłoszono wyjątek: naruszenie dostępu do zapisu. this->**_Myproxy** było 0xFDFDFDFD." oraz przenosi mnie linii 239 pliku xutility. 
Moja domyślna capacity to 10. Kiedy do tablicy dodaję np. 3 stringi to wszystko działa poprawnie. Program działa poprawnie dla charów i intów.
Czy może być to spowodowane złym zwalnianiem pamięci lub jakimś wskaźnikiem wskazującym na jakąś głupotę? Czemu więc program działa dla intów i charów?
Poniżej wklejam kod:
C/C++
#include "pch.h"
#include <iostream>
#include <string>
#include <time.h>
using namespace std;

template < typename T >
class Arr
{
    T * data;
    int capacity, len;
public:
    Arr()
    {
        capacity = 10;
        len = 0;
        data = new T[ capacity ];
    }
    ~Arr()
    {
        delete[] data;
    }
    void add( T value )
    {
        if( capacity <= len ) //powiekszenie jesli nie ma miejsca
        {
            capacity = 2 * capacity;
            T * temp = new T[ capacity ];
            for( int i = 0; i <= len; i++ )
            {
                //temp[i] = data[i];
                temp[ i ] = move( data[ i ] );
               
            }
            delete[] data;
            data = temp;
        }
        data[ len++ ] = value;
    }
    const T retVal( const int index )
    {
        if( index >= len )
        {
            cout << "Nie ma elementu o takim indeksie, zwracam wartosc el. [0]: ";
            return this->data[ 0 ];
        }
        else
             return this->data[ index ];
       
    }
    void change( int index, T new_data )
    {
        if( index > len )
        {
            cout << "Nie ma takiego elementu" << endl;
            return;
        }
        data[ index ] = new_data;
    }
    void clean()
    {
        if( len == 0 )
        {
           
            cout << "Tablica pusta!" << endl;
            return;
        }
        len = len - 1;
        for( int i = len; i >= 1; --i )
        {
            data[ i ].~T();
            len--;
        }
    }
    void getData()
    {
        cout << endl << "Akt. pojemnosc tablicy: " << capacity << endl;
        cout << "Liczba el. w tablicy: " << len << endl;
    }
    void delLast()
    {
        data[ len-- ].~T();
    }
    void printArr()
    {
        for( int i = 0; i < len; i++ )
        {
            cout << data[ i ] << " ";
        }
        //cout << "Koniec" << endl;
    }
   
   
   
};
string randomString( int length )
{
    string rs;
    static const char chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    int size = sizeof( chars );
    for( int i = 0; i < length; i++ )
    {
        rs = rs + chars[ rand() %( size - 1 ) ];
    }
    return rs;
}
int main()
{
    Arr < string > * tab = new Arr < string >();
    const int order = 7;
    const int n = pow( 10, order );
    clock_t start = clock();
    double max_time_per_element = 0.0;
    srand( time( 0 ) );
    for( int i = 0; i < n; i++ )
    {
        string el = randomString( 3 );
        clock_t start2 = clock();
        tab->add( el );
        clock_t stop2 = clock();
        double time_per_element =( stop2 - start2 ) / CLOCKS_PER_SEC; // obliczenie czasu pojedynczej operacji dodawania
        if( time_per_element > max_time_per_element )
        {
            time_per_element = max_time_per_element;
            cout << max_time_per_element << endl;
        }
    }
    clock_t stop = clock();
    double general_time =( stop - start ) / CLOCKS_PER_SEC;
    tab->getData();
    cout << "Czas calej operacji to: " << general_time << endl;
    tab->printArr();
    tab->clean(); // czyszczenie tablicy wraz z uwalnianiem pamieci danych
    delete tab;
    return 0;
}
P-175496
pekfos
» 2019-11-07 00:40:47
C/C++
for( int i = 0; i <= len; i++ )
Przekraczasz zakres tablicy.

C/C++
data[ i ].~T();
To jest błędne.
P-175497
greenbanzai
Temat założony przez niniejszego użytkownika
» 2019-11-07 10:02:40
Dziękuje za pomoc, racja, po poprawce program śmiga. Tak z ciekawości, dlaczego przekraczając zakres tablicy, kiedy w mojej tablicy przechowywałem inty czy chary program działał, a dla stringów się wysypywał? Po prostu ciekawi mnie powód.
Co w
data[ i ].~T();
 jest źle? Myślałem, że po prostu dla pola data o indeksie zaczynającym się od len-1 czyli ostatniego elementu schodzę w dół usuwając ostatni element z tablicy aż nie dojdę do ostatniego elementu, gdzie zmniejszam długość o 1 i uzyskuję pustą tablicę. Jeśli się mylę to proszę o poprawienie mnie.
C/C++
void clean()
{
    if( len == 0 )
    {
       
        cout << "Tablica pusta!" << endl;
        return;
    }
    len = len - 1;
    for( int i = len; i >= 1; --i )
    {
        data[ i ].~T();
        len--;
    }
P-175500
pekfos
» 2019-11-07 17:56:39
Tak z ciekawości, dlaczego przekraczając zakres tablicy, kiedy w mojej tablicy przechowywałem inty czy chary program działał, a dla stringów się wysypywał? Po prostu ciekawi mnie powód.
W obu przypadkach program jest błędny. Przekroczenie zakresu tablicy powoduje interpretowanie jako obiekt pamięci, która takiego obiektu nie zawiera. W przypadku int trzeba odpowiedniej architektury procesora, żeby błędna reprezentacja sama z siebie spowodowała błąd. std::string zawiera wskaźniki, a odwoływanie się do przypadkowych adresów w pamięci ma znacznie większe szanse wywołać fajerwerki.

Myślałem, że po prostu dla pola data o indeksie zaczynającym się od len-1 czyli ostatniego elementu schodzę w dół usuwając ostatni element z tablicy aż nie dojdę do ostatniego elementu
To nie jest usuwanie elementu, tylko wywołanie destruktora. Coś, po czym obiekt jest całkowicie nieużywalny, nie lepszy niż niezainicjalizowana pamięć. Przypisanie w to miejsce nowej wartości to za mało. Do tego delete automatycznie wywołuje destruktory dla wszystkich elementów tablicy, więc finalnie będziesz mieć je wywołane po kilka razy, co jest zawsze błędne.
P-175501
« 1 »
  Strona 1 z 1