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

Crash na windowsie przy przypisywaniu wartości z wektora do tablicy

Ostatnio zmodyfikowano 2017-05-14 17:07
Autor Wiadomość
Szustarol
Temat założony przez niniejszego użytkownika
Crash na windowsie przy przypisywaniu wartości z wektora do tablicy
» 2017-05-12 08:58:14
Może najpierw kod:
main:
C/C++
#include <iostream>
#include "Vector2D.h"

int main()
{
    Vector2D < int > test( 0, 0 );
    int testarray[ 2 ][ 3 ] =
    {
        { 10, 10, 5 },
        { 2, 4, 1 }
    };
   
    for( int i = 0; i < 2; i++ )
    {
        for( int j = 0; j < 3; j++ )
        {
            std::cout << testarray[ i ][ j ] << ", ";
        }
        std::cout << std::endl;
    }
    test.FromArray(( int * ) testarray, 2, 3 );
   
    int ** ret = test.ToArray(); //tutaj crash leci
   
    for( int i = 0; i < test.GetHeight(); i++ )
    {
        for( int j = 0; j < test.GetWidth(); j++ )
        {
            std::cout << ret[ i ][ j ] << ", ";
        }
        std::cout << std::endl;
    }
}

vector2d.h:
C/C++
#ifndef VECTOR2D_H
#define VECTOR2D_H
#include <vector>

template < class T >
class Vector2D
{
public:
    Vector2D( int width, int height );
    ~Vector2D();
    T ** ToArray();
    void FromArray( T *, int, int );
    int GetWidth();
    int GetHeight();
protected:
   
private:
    int Width, Height;
    bool ArraySet;
    T ** Array;
    std::vector < T >* LinearVector;
};

#endif // VECTOR2D_H
vector2d.cpp:
C/C++
#include "Vector2D.h"
#include <iostream>

template < class T > Vector2D < T >::Vector2D( int height, int width )
{
    this->Width = width;
    this->Height = height;
    this->LinearVector = new std::vector < T >;
    this->LinearVector->resize( width * height );
    this->ArraySet = false;
}

template < class T > Vector2D < T >::~Vector2D()
{
    delete( this->LinearVector );
    if( this->ArraySet );
   
    delete( this->Array );
}

template < class T > T ** Vector2D < T >::ToArray()
{
    if( this->ArraySet )
         delete( this->Array );
   
    this->ArraySet = true;
    this->Array = new T *[ this->Height ];
    for( int i = 0; i < this->Height; i++ )
         this->Array[ i ] = new T[ this->Width ];
   
    for( int y = 0; y < this->Height; y++ )
    for( int x = 0; x < this->Width; x++ )
         this->Array[ y ][ x ] = this->LinearVector->at( this->Width * y + x ); //Crash na tej linijce
   
    return this->Array;
}

template < class T > void Vector2D < T >::FromArray( T * arr, int height, int width )
{
    this->Width = width;
    this->Height = height;
    delete( this->LinearVector );
    this->LinearVector->resize( width * height );
    for( int y = 0; y < height; y++ )
    {
        for( int x = 0; x < width; x++ )
        {
            this->LinearVector->at( y * width + x ) = *( arr + x + y * width );
        }
    }
   
}

template < class T > int Vector2D < T >::GetWidth()
{
    return this->Width;
}

template < class T > int Vector2D < T >::GetHeight()
{
    return this->Height;
}

template class Vector2D < int >;
template class Vector2D < char >;
template class Vector2D < std::string >;
template class Vector2D < float >;
template class Vector2D < double >;

Jak widać próbuję zrobić klasę, która przechowuje logiczną tablicę dwuwymiarową jako pojedynczy wektor
w kodzie oznaczyłem miejsce crasha,
co ciekawe:

this->Array[y][x] = this->LinearVector->at(this->Width*y + x); - oczywiście nie zadziała
this->Array[y][x] = 0; - już zadziała
std::cout << this->LinearVector->at(this->Width*y + x) << ", "; - także zadziała
więc pozornie wszystko powinno być ok, bo wartości są poprawne po tym jak sprawdzałem tylko nie wiem czemu
przypisanie z tego wektora nie działa.
Dzięki z góry za pomoc
P-160979
Monika90
» 2017-05-12 09:48:57
W funkcji FromArray jest coś takiego
C/C++
delete( this->LinearVector );
this->LinearVector->resize( width * height );

P-160981
darko202
» 2017-05-12 10:20:53
1.
mnie zastanawia to, że 
T ** Array;
chyba powinno być zainicjalizowane
jak np. na
https://www.tutorialspoint.com​/cplusplus​/cpp_pointer_to_pointer.htm
C/C++
int var;
int * ptr;
int ** pptr;

var = 3000;

// take the address of var
ptr = & var;

// take the address of ptr using address of operator &
pptr = & ptr;

w konstruktorze tego nie ma, a w main od razu odwołujesz się do metody
 
test.FromArray(( int * ) testarray, 2, 3 );

a w niej nie ma inicjalizacji
dlatego Array[ y ][ x ]  jest odwołaniem się do pustki

2.
mógłbyś dołożyć komunikat błędu jaki otrzymujesz
bo dziś znów jestem zbyt leniwy, aby odtwarzać Twój błąd
Sorry

3.
poznaj technikę debugowania kodu - sporo ułatwia

uruchamiam program -> zatrzymuję się przed linia błędu -> oglądam stan zmiennych
i bardzo często błąd jest szybko namierzany (choć czasem po n tym podejściu)

Powodzenia :)
P-160982
Szustarol
Temat założony przez niniejszego użytkownika
» 2017-05-12 15:37:18
dzięki Monika, faktycznie nie zauważyłem tego

delete( this->LinearVector );
to teraz jeszcze jedno pytanko
macie jakiś pomysł jak zmienić funkcję fromarray, aby nie trzeba było castować, np. jak do (int*) na powyższym przykładzie?
P-161002
Monika90
» 2017-05-12 16:30:09
Spróbuj z szablonem
C/C++
template < class T >
class Vector2
{
public:
    template < class U, std::size_t width, std::size_t height >
    void from_array( const U( & array )[ height ][ width ] )
    {
    }
};
P-161003
Szustarol
Temat założony przez niniejszego użytkownika
» 2017-05-14 14:57:11
czy taki szablon wymaga definiowania ciała funkcji w pliku nagłówkowym?
jak się do niego odnieść w .cpp?
Poza tym, jeśli chcę aby szablon był "dynamiczny" a nie tylko dla typów które określam na dole pliku .cpp,
to muszę ciała funkcji definiować w pliku .h?
P-161089
Monika90
» 2017-05-14 17:07:26

Poza tym, jeśli chcę aby szablon był "dynamiczny" a nie tylko dla typów które określam na dole pliku .cpp,
to muszę ciała funkcji definiować w pliku .h?
Tak. No chyba że używasz go tylko w jednym pliku cpp, to wtedy definicja może być tylko w tym pliku.


C/C++
template < class U, std::size_t width, std::size_t height >
void from_array( const U( & array )[ height ][ width ] )
{
}

Parametrami tego szablonu są wymiary tablicy, więc musiałbyś dokonać jawnego konkretyzowania dla wszystkich możliwych wymiarów które chcesz użyć, co jest niepraktyczne, więc jego definicja musi być w pliku nagłówkowym.


I jeszcze jedno,
class U
 jest tam po to żeby można było wywołać from_array z argumentem kompatybilnego typu, np.
C/C++
Vector2D < int > v; //wektor intów
float a[ 5 ][ 7 ] = { }; //a tablica floatów
v.from_array( a );
Jeżeli chcesz bardziej ścisłego dopasowania, to usuń class U, a U zastąp przez T
C/C++
template < class T >
class Vector2d
{
public:
    template < std::size_t width, std::size_t height >
    void from_array( const T( & array )[ height ][ width ] )
    {
    }
};
P-161091
« 1 »
  Strona 1 z 1