Metody (template) dla array helper'a

Odpowiedz Nowy wątek
2018-05-06 20:48
0

Panowie,

Zaczynam sobie przygotowywac custom helper'a dla wielowymiarowych tablic. Zaczalem od dwoch metod template:
1) inicjalizacja tablicy:

        template <typename T>
        T** initArr2DT(T** arr2DPtr, int iLength, int jLength)
        {
            arr2DPtr = new T*[iLength];

            for (int i = 0; i < iLength; i++)
            {
                arr2DPtr[i] = new T[jLength];

                memset(arr2DPtr[i], '\0', sizeof(arr2DPtr[i]));
            }

            return arr2DPtr;
        }

2) kopiowanie tablicy:

        template <typename T>
        T** copyArr2DT(T** arr2DPtr, T** arr2DCopyPtr, int iLength, int jLength)
        {
            arr2DCopyPtr = new T*[iLength];

            for (int i = 0; i < iLength; i++)
            {
                arr2DCopyPtr[i] = new T[jLength];

                for (int j = 0; j < jLength; j++)
                {
                    arr2DCopyPtr[i][j] = arr2DPtr[i][j];
                }
            }

            return arr2DCopyPtr;
        }

Prosze o ich ocene i ewentualne wskazowki co do ulepszenia kodu.
Z gory dziekuje :)

Pozostało 580 znaków

2018-05-06 22:20
5

Obie funkcje różnią się tylko jedną linijką. (DRY)

Nie chcę być złośliwy, ale w C++ kopiowanie wielowymiarowej tablicy(std::vector czy std::array) wygląda tak:

secondArray = firstArray;

Pozostało 580 znaków

2018-05-06 23:07
0
tajny_agent napisał(a):

Obie funkcje różnią się tylko jedną linijką. (DRY)

1) W pierwszym przypadku potrzebuje jedynie pustej zainicjowanej tablicy do ktorej moge wpisac w petli wartosci odczytywane z pliku

tajny_agent napisał(a):

Nie chcę być złośliwy, ale w C++ kopiowanie wielowymiarowej tablicy(std::vector czy std::array) wygląda tak:

secondArray = firstArray;

2) Alez bron Cie Panie Boze :). W drugim przypadku chodzi o to ze kopiowana tablica (arr2DPtr) w zalozeniu jest lokalna w ciele pewnej metody klasy, natomiast kopiujaca (arr2DCopyPtr) jest tej samej klasy atrybutem. I tutaj jest problem bo w przypadku kopiowania o ktorym mowisz oba wskazniki sa identyczne. Kiedy metoda konczy swoje dzialanie szlak trafia tablice arr2DPtr co (o ile dobrze rozumiem zawilosci w kwestii wskaznikow w C++) ma fatalne konsekwencje dla arr2DCopyPtr. Zatem w skrocie chodzilo mi o skopiowanie wartosci z jednej tablicy do drugiej a nie jej klonowanie w przypadku kiedy obie maja rozny zasieg.
Oczywiscie jest wysoce prawdopodobne, ze moge nie brac pewnych istotnych rzeczy pod uwage (c++ to nie moja bajka, jestem php-owcem), ale wg mojego aktualnego (niewielkiego zreszta) stanu wiedzy wlasnie w taki sposob moge sobie poradzic.

Jesli masz jakies sugestie mogac mi pomoc rozwiazac te zagwozdke - bede szczerze wdzieczny.

edytowany 1x, ostatnio: Constantic, 2018-05-06 23:08

Pozostało 580 znaków

2018-05-07 00:11
3
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using Vec2Int = std::vector<std::vector<int>>;

template <typename C>
void Copy(const C& src, C& dest) {
   dest = src;
}

template <typename C>
void LocalCopy(C& coll) {
   C loclaColl{ {11, 22, 33}, {44, 55, 66} };
   Copy(loclaColl, coll);
}

template <typename C>
void Mult(C& coll, int n) {
   for (auto& dimension : coll) {
      std::transform(
         dimension.cbegin(), dimension.cend(), 
         dimension.begin(), 
         [=](auto& el) { return el * n; });
   }
}

template <typename C>
void Print(const C& coll, const std::string& opt = "") {
   if (!opt.empty()) { std::cout << opt << &coll << '\n'; }
   for (auto const& firstDimension : coll) {
      for (auto const& secondDimensionElement : firstDimension) {
         std::cout << secondDimensionElement << ' ';
      }
      std::cout << '\n';
   }
   std::cout << std::endl;
}

int main() {
   Vec2Int arr1{ { 1, 2, 3 }, {4, 5, 6 } };
   Vec2Int arr2;
   Vec2Int arr3;
   Copy(arr1, arr2);
   Print(arr1, "arr1");
   Mult(arr2, 3);
   Print(arr2, "arr2");
   LocalCopy(arr3);
   Mult(arr3, 2);
   Print(arr3, "arr3");
}

Czy o to chodziło?
https://wandbox.org/permlink/qsQGvyLXsVDZxfRH

Można też użyć jednowymiarowej tablicy z widokiem dwuwymiarowym.


Nie pisz na priv. Zadaj dobre pytanie na forum.
edytowany 4x, ostatnio: YooSy, 2018-05-07 00:21

Pozostało 580 znaków

2018-05-07 00:54
1

A samo std::copy sobie tu nie da sobie rady?
Dobra rada tak ogólnie: wyrzuć książki/tutoriale do C++, których używasz.i zapomnij, że nie new i delete w ogóle istnieją.

Da radę, chciałem pokazać samą ideę. - YooSy 2018-05-07 00:55

Pozostało 580 znaków

2018-05-07 10:11
2

Ten memset w przypadku bliżej nieokreślonego typu T jest błędem (zresztą źle go używasz). Jeśli T może być czymś więcej niż typem liczbowym, zastanowiłbym się nad użyciem std::allocator.

PS. ten sposób tworzenia tablicy 2D nie jest zbyt optymalny pamięciowo.

edytowany 1x, ostatnio: _0x666_, 2018-05-07 10:13

Pozostało 580 znaków

2018-05-07 11:10
0

Panowie,

Wszystkim bardzo dziekuje za konstruktywne wypowiedzi.

Pozostało 580 znaków

2018-05-07 12:53
1
Constantic napisał(a):

2) Alez bron Cie Panie Boze :). W drugim przypadku chodzi o to ze kopiowana tablica (arr2DPtr) w zalozeniu jest lokalna w ciele pewnej metody klasy, natomiast kopiujaca (arr2DCopyPtr) jest tej samej klasy atrybutem. I tutaj jest problem bo w przypadku kopiowania o ktorym mowisz oba wskazniki sa identyczne. Kiedy metoda konczy swoje dzialanie szlak trafia tablice arr2DPtr co (o ile dobrze rozumiem zawilosci w kwestii wskaznikow w C++) ma fatalne konsekwencje dla arr2DCopyPtr. Zatem w skrocie chodzilo mi o skopiowanie wartosci z jednej tablicy do drugiej a nie jej klonowanie w przypadku kiedy obie maja rozny zasieg.
Oczywiscie jest wysoce prawdopodobne, ze moge nie brac pewnych istotnych rzeczy pod uwage (c++ to nie moja bajka, jestem php-owcem), ale wg mojego aktualnego (niewielkiego zreszta) stanu wiedzy wlasnie w taki sposob moge sobie poradzic.

W kwestii wskaźników oczywiście masz rację. Kopiowanie wskaźnika nie powoduje skopiowania wszystkiego co się pod nim tak naprawdę kryje(o to właśnie chodzi we wskaźnikach :P).
Dlatego zasugerowałem użycie klasy std:vector lub std:array. Nie musisz sobie zawracać głowy alokowaniem/zwalnianiem pamięci, kopiowanie odbywa się za pomocą zwykłego operatora przypisania = i dodatkowo oferują kilka pomocnych funkcji. Prostsze jest również ich użycie w funkcjach z <algorithm>.

Pozostało 580 znaków

2018-05-07 14:24
0

Panowie jesli mozna pojsc za ciosem to mam pytanie w zwiazku z "vector".

Otoz w jednym z naglowkow aplikacji "zapodalem" sobie taka definicje typu:

//ArrayHelper.h
//...
typedef std::vector<std::vector<string>> ArrString2D;

namespace CoreHelper
{
    class ArrayHelper
    {
    //...
    }
}

Zakladajac, iz w ten sposob bedzie ona dostepna globalnie - i tutaj pierwsze pytanie - czy praktyczniej nie bedzie umiescic definicji od razu w czasie "odpalenia" aplikacji ?
Ok, ale przejdzmy do meritum.
W innym miejscu chce wykorzystac zdefiniowany przez siebie typ w przypadku lokalnej tablicy, ale w ponizszym przypadku

//DataReader.cpp

ArrString2D DataReader::readFromFile(string file)
{
    ArrString2D arrString2D(*rowsNumberPtr, vector<string>(*colsNumberPtr));
}

Na gwiazdce "*rowsNumberPtr" wywala mi blad "no istance of constructor...". Sprobowalem zatem czegos takiego:

//DataReader.cpp

ArrString2D DataReader::readFromFile(string file)
{
    ArrString2D arrString2D(*rowsNumberPtr);
        //...
    while (!reader.eof()) {
        //...
        vector<string> col(*colsNumberPtr);
        //...
        while ((pos = line.find(delimiter)) != string::npos) {
        //...
            col.at(j) = line.substr(0, pos);
        //...
        }
        //...
        arrString2D.at(i).resize(*colsNumberPtr);
        arrString2D.at(i) = col;
        //...
    }
        //...        
}

Ale w momencie przypisania: "arrString2D.at(i) = col;" pojawia sie kolejny blad : "no operator "=" matches these operands".

Jesli jednak zrobie cos takiego:

//DataReader.cpp

ArrString2D DataReader::readFromFile(string file)
{
    vector<vector<string>> arrString2D(*rowsNumberPtr, vector<string> (*rowsNumberPtr));
}

Przypisanie dziala bez zarzutu, ale typ "vector<vector<string>>" deklarowany w ciele metody nie jest tozsamy z "typedef std::vector<std::vector<string>> ArrString2D;" :/

W jaki zatem sposob powinienem postapic ?
Z gory dziekuje za sugestie.

edytowany 2x, ostatnio: Constantic, 2018-05-07 15:09
co to jest rowsNumberPtr ? Wskaźnik na int? - revcorey 2018-05-07 15:12

Pozostało 580 znaków

2018-05-07 15:06

przejże sobie dokładnie jak wrócę z pracy ale:

  • using zamiast typedef
ArrString2D arrString2D(*rowsNumberPtr, vector<string>(*colsNumberPtr));

Co ty chcesz tu zrobić? masz typ vector<vector<>> i skąd weźmiesz taki konstruktor? Po prostu zrób tak

ArrString2D arrString2D;
// rezerwacja pamięci i dodawanie wektorów przez emplace_back itd. czy jakieś inne listy inicjalizacyjne. sprawdź dokumentacje

http://en.cppreference.com/w/cpp/container/vector

at() rzuca wyjątkami jak pamiętam do tego:
https://stackoverflow.com/que[...]-a-vector-with-another-vector


We are the 4p. Existence, as you know it, is over. We will add your biological and technological distinctiveness to our own. Resistance is futile

Pozostało 580 znaków

2018-05-07 15:27
0
revcorey napisał(a):
ArrString2D arrString2D;
// rezerwacja pamięci i dodawanie wektorów przez emplace_back itd. czy jakieś inne listy inicjalizacyjne. sprawdź dokumentacje

Works like a charm :D. Wczesniej probowalem identycznej deklaracji ale "sypalo" mi sie na push_back'u wiec nawet nie probowalem z emplace_back, a jednak okazalo sie, ze powinienem byl.

Bardzo Ci dziekuje.

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0