Konstruktor kopiujący na skróty

0

Cześć, mam takie pytanie:
zrobiłem sobie klasę w której mam dynamiczną tablicę. W związku z tym muszę zrobić m.in. własny operator przypisania oraz konstruktor kopiujący. W obu przypadkach kod wygląda podobnie. Zastanawiam się jednak czy można iść na skróty i mając prawidłowo stworzony operator przypisania zrobić takie coś:

Klasa& Klasa::operator=(const Klasa& copy)
{
if(&copy == this)
return *this;

if(tablica)
delete[] tablica;

tablica = new double[copy.size];
for(int i=0; i<size; i++)
tablica[i] = copy.tablica[i];
//...
}
Klasa::Klasa(Klasa& copy)
{
*this = copy;
}

Co Wy na to? Czy to jest poprawne? Czy są w związku z tym jakieś niebezpieczeństwa?

0

Jeżeli już to na odwrót:

Klasa::Klasa(const Klasa &copy):size(copy.size),tablica(new double[copy.size])
  {
   for(size_t i=0;i<size;++i) tablica[i]=copy.tablica[i];
  }

void Klasa::Swap(Klasa &copy)
  {
   ::swap(size,copy.size);
   ::swap(tablica,copy.tablica);
  }

Klasa &Klasa::operator=(const Klasa &copy)
  {
   Klasa Tmp(copy);
   Swap(Tmp);
  }
0

Dziękuję Wam bardzo za zainteresowanie się tematem i prowadzenie ciekawej dyskusji ;)
Na początku śpieszę z wyjaśnieniem:
tak, komentarz typu //... miał sugerować, że cała reszta będzie poniżej. Skoncentrowałem się tylko na kopiowaniu tablicy dynamicznej, gdyż tylko to wymusza w moim przypadku utworzenie konstruktora kopiującego, przypisania i destruktora (który tutaj został pominięty).

Jeśli chodzi o używanie vectora lub jego pochodnych to nie zawsze jest to tak kolorowe rozwiązanie. Fakt, jest to wygodne rozwiązanie w większości przypadków, ale gdy naprawdę zależy nam na szybkości wykonywanych obliczeń (a to jest u mnie priorytetem) to znacznie lepszym rozwiązaniem jest korzystanie z tablic dynamicznych i odwoływanie się do nich bezpośrednio. Jest to związane z tym, że korzystając z klasy vector za każdym razem wywołujemy funkcję co jest dość kosztowne.
Poniżej umieszczam moje proste testy, z których wynika, że odwoływanie się bezpośrednio do zmiennej wbudowanej (np. double) jest kilkanaście razy szybsze niż odwoływania się do innych obiektów). Co ciekawe klasa vector w moim teście wypada znacznie gorzej od mojej wersji (pseudo) vectora (zrobiona tylko na potrzeby testów - bez żadnych zabezpieczeń i dodatkowych funkcji).
Wyniki są następujące:
zwykła zmienna: czas wykonania: 2,49 s.
vector: czas wykonania: 41,76 s.
Mój pseudo-vector: czas wykonania: 21,78 s.

Kod testu jest następujący:

#include <iostream>
#include <time.h>
#include <random>
#include <vector>

using namespace std;

class vector2
    {
    public:
        double* tab;
        int size;
        double& operator[](int i)
            {
            return tab[i];
            }

        vector2(int s) : size(s)
            {
            tab = new double[size];
            }
        ~vector2(){delete[] tab;}
    };

int _tmain(int argc, _TCHAR* argv[])
    {
    clock_t start, stop, sum1, sum2, sum3;

    int size = 10000;
    int iter = 100000;
    double* tab1 = new double[size];
    vector<double> tab2(size);
    vector2 tab3(size);

    for(int i = 0; i < size; i++)
        {
        tab1[i] = rand() / (double)RAND_MAX;
        tab2[i] = tab1[i];
        tab3[i] = tab1[i];
        }

    double parametr = 0.12345;
    double wynik1 = 0.0;
    double wynik2 = 0.0;
    double wynik3 = 0.0;

    cout << "czas start" << endl;

    start = clock();
    for(int i = 0; i < iter; i++)
        {
        wynik1 = 0.0;
        for(int j = 0; j < size; j++)
            {
            wynik1 += tab1[j] * parametr;
            }
        }
    stop = clock();
    sum1 = stop - start;

    start = clock();
    for(int i = 0; i < iter; i++)
        {
        wynik2 = 0.0;
        for(int j = 0; j < size; j++)
            {
            wynik2 += tab2[j] * parametr;
            }
        }
    stop = clock();
    sum2 = stop - start;

    start = clock();
    for(int i = 0; i < iter; i++)
        {
        wynik3 = 0.0;
        for(int j = 0; j < size; j++)
            {
            wynik3 += tab3[j] * parametr;
            }
        }
    stop = clock();
    sum3 = stop - start;

    cout << "czas1 = " << (double)sum1 / 1000.0 << endl;
    cout << "czas2 = " << (double)sum2 / 1000.0 << endl;
    cout << "czas3 = " << (double)sum3 / 1000.0 << endl;

    cout << "wynik1 = " << wynik1 << endl;
    cout << "wynik2 = " << wynik2 << endl;
    cout << "wynik3 = " << wynik3 << endl;

    //-----

    getchar();
    return 0;
    }

Jeśli chodzi o Twój przykład @_13h_Dragon to ok, rzeczywiście tak też można ;). Ale dlaczego nie na odwrót? Ten mój sposób wydaje się nieco prostszy ;) Czy nie uważasz, że tak jak ja to zrobiłem również jest ok? A jeśli nie to dlaczego?

Pozdrawiam

0

Uuu, a to dziwne... Podobne testy robiłem na swoim starym komputerze i również korzystanie z klasy vector lub ogólnie z obiektów dawało znacznie gorsze wyniki...
@Sopelek a możesz napisać w jakim środowisku wykonałeś powyższy kod?
Jeśli chodzi o mnie to ja testy wykonałem w VS 2013 Express -> czy wersja pro może powodować szybsze wykonywanie obliczeń?!? O_o
Jeśli ktoś jeszcze wykonał powyższy kod to bardzo proszę o podanie wyników.
pozdrawiam

0

Hmm, teraz tak doszło do mnie, że przecież można zastosować funkcje inline, które powinny wyeliminować wydłużenie czasu wykonywania operacji związanych z wywoływaniem funkcji... Do tego w mojej klasie teoretycznie funkcja operator[] jest inline (jest zadeklarowana wewnątrz klasy). Nie wiem tylko dlaczego są w takim razie takie rozbieżności w szybkości wykonywanych obliczeń... ;-(
Ma ktoś jakiś pomysł co może być przyczyną?

1

No dobra, chyba znalazłem przyczynę tak dużych rozbieżności: ja kompilowałem swój kod jako debug a nie release. Po zmianie na Release czas wykonywania kodu wynosi około 0,83 s. dla wszystkich wersji.

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