PDA

View Full Version : [C++] costruttori di copia e operatori assegnamento problem :-(


Zero-Giulio
19-07-2010, 12:02
Ecco un breve pezzo di codice con una classe che sto scrivendo



template <typename T>
class array {

template <typename U>
friend class array;

friend ostream & operator << (ostream & os, const array <T> & v) {
cout << endl;
for (unsigned int i = 0; i < v.num_; i++)
cout << v.ptr [i] << " ";
for (unsigned int i = v.num_; i < v.size_; i++)
cout << "? ";
cout << endl;
return os;
}

public:

explicit array (const unsigned int & s)
: incr_ (s)
, size_ (s)
, num_ (0) {
alloc ();
}

explicit array (const unsigned int & s, const unsigned int & i)
: incr_ (i)
, size_ (s)
, num_ (0) {
if (incr_ < 1) {
arrayWarning ("in array constructor: incr_ must be a >= 1 unsigned int");
incr_ = 1;
}
alloc ();
}

template <typename U>
array (const array <U> & a)
: incr_ (a.incr_)
, size_ (a.size_)
, num_ (a.num_) {
alloc ();
for (unsigned int i = 0; i < num_; i++)
ptr [i] = static_cast <T> (a.ptr [i]);
}

~array () {
delete [] ptr;
}

template <typename U>
bool operator != (const array <U> & a) const {
if (num_ != a.num_)
return true;
for (unsigned int i = 0; i < num_; i++)
if (ptr [i] != a.ptr [i])
return true;
return false;
}

template <typename U>
bool operator == (const array <U> & a) const {
return !(*this != a);
}

template <typename U>
const array <T> & operator = (const array <U> & a) {
if (size_ < a.num_)
add (a.size_);
num_ = a.num_;
for (unsigned int i = 0; i < num_; i++)
ptr [i] = static_cast <T> (a.ptr [i]);
return *this;
}

template <typename U>
array <T> & in (const U & u) {
add (1);
ptr [num_++] = static_cast <T> (u);
return *this;
}

template <typename U>
array <T> & in (const array <U> & a) {
unsigned int n = a.num_;
add (n);
for (unsigned int i = 0; i < n; i++)
ptr [num_++] = static_cast <T> (a.ptr [i]);
return *this;
}

unsigned int setIncr (const unsigned int & i) {
unsigned int dummie = incr_;
if (i < 1)
arrayWarning ("in setIncr: function parameter must be a >= 1 unsigned int");
else
incr_ = i;
return dummie;
}

unsigned int incr () const {
return incr_;
}

unsigned int size () const {
return size_;
}

unsigned int num () const {
return num_;
}

private:

void alloc () {
if (size_ < 1)
arrayError ("in array constructor: size_ must be a >= 1 unsigned int");
try {
ptr = new T [size_];
}
catch (bad_alloc & err_msg) {
arrayAllocationError (Str (size_));
}
}

void add (const unsigned int & n) {
unsigned int min_size = num_ + n;
if (size_ < min_size) {
size_ = max (size_ + incr_, min_size);
T * new_ptr;
try {
new_ptr = new T [size_];
}
catch (bad_alloc & err_msg) {
arrayAllocationError (Str (size_));
}
for (unsigned int i = 0; i < num_; i++)
new_ptr [i] = ptr [i];
delete [] ptr;
ptr = new_ptr;
}
}

unsigned int incr_;
unsigned int size_;
unsigned int num_;
T * ptr;

};



Come potete vedere, ci sono costruttori, costruttori di copia, operatori relazionali e di assegamento e altro.
Il costruttore di copia e quello di assegnamento sono scritti come template.
Mi domando se questo crei problemi.

Il punto è questo:

1) se faccio

array <double> a1 (4);
array <double> a2 (8);

a2 = a1

il codice funziona (a2 mantiene size_ e incr_ e riceve da a1 num_ e i primi num_ elementi di ptr).

2) se invece ho

array <double> a1 (4);
array <double> a2 (8);

a2 = a1

il codice non funziona (a2 riceve anche size_ e incr_ da a1).
Ho cercato di debuggare il codice cercando di capire perchè questo succedesse e ho scoperto che
l'operazione a2 = a1 NON chiama nè il mio operatore di assegnamento, nè altri mie funzioni.
Ho messo delle cout dentro tutta la mia classe ma niente.
Se scrivo a2 = a1, con i tipi di a1 e a2 uguali, viene invocato qualcosa che io non ho scritto.

Ora io mi domando, sarà mica che quello scemo del compilatore invoca un qualche costruttore implicito o
qualche operatore che solo lui sa (quelli che invoca quando un utente non li crea per intenderci)?
Oppure sono io lo scemo e c'è qualcosa che non so?

E nel caso il compilatore usasse qualcosa di suo... Perchè lo fa?
E' per via del fatto che io ho usato i template?

Ma se io scrivo

template <typename U> const array <T> & operator = (const array <U> & a)

non dovrei avere come caso particolare anche

const array <T> & operator = (const array <T> & a)

???

Non capisco.

P.S.: se aggiungo un costruttore di copia e un operatore di assegnamento senza i template tutto funziona.
E' solo che non piace riempire il codice di funzioni ridondanti. Insomma,

const array <T> & operator = (const array <T> & a)

dovrebbe essere un caso particolare di

template <typename U> const array <T> & operator = (const array <U> & a)

no?
Perchè doverli scrivere entrambi???