Pracuję nad prostym klasą szablon matrycy do celów praktyki, zdefiniowałem mój konstruktor i destruktor, ale w sprawie testowania klasy, dowiedziałem się, że operacje ruchu i kopiowania działa bez żadnych wad i nie zdefiniowałem ich. Naprawdę nie rozumiem, co idzie i nie ufam, co się dzieje.

#ifndef MATRIX_H_
#define MATRIX_H_

#include <cstdlib>
#include <iostream>

namespace mat
{
    template<class T>
    class Matrix
    {
        public:
            Matrix(size_t row, size_t column, const T& val)
                : row_{row}, column_{column}, elem_{static_cast<T*>(::operator new(row_ * column_))} 
                {
                    for(size_t i = 0; i != size(); ++i )
                        elem_[i] = val;
                }
            Matrix(size_t row, size_t column)
                :  row_{row}, column_{column}, elem_{static_cast<T*>(::operator new(row_ * column_))} {}
            
            size_t size() const { return row_ * column_; }

            ~Matrix()
            {
                for(size_t i = size(); i != 0; --i)
                {
                    elem_[i].~T();
                    delete elem_;
                }
            }
        private:
            size_t row_;
            size_t column_; 
            T *elem_;
    };
}

#endif
#include <iostream>
#include "Matrix.h"

using namespace mat;

class SomeClass
{
    int s_;
    public:
        SomeClass(int s ) : s_{s} {} 
};

template<class T>
Matrix<T> fn(const Matrix<T> A)
{
    return A;
}

int main()
{
    SomeClass s{1};
    Matrix<SomeClass> my_mat(2, 3, s);
    Matrix<int> my_mat2(2, 3, 4);
    Matrix<SomeClass> my_mat3{2, 3};
    Matrix<int> copy_mat(my_mat2);
}

c++
0
theProgrammer 22 listopad 2020, 00:58

1 odpowiedź

Najlepsza odpowiedź

Jeśli nie deklarujesz funkcji specjalnej, a następnie czasami kompilator daleko deklaruje i / lub określa funkcje.

Zobacz tabelę w tej odpowiedzi, aby uzyskać więcej szczegółów.

Twój kod powoduje niezdefiniowane zachowanie na kilka sposobów; Jeden możliwy wzrost nieokreślonych zachowań pojawia się poprawnie - na razie. Należy wpaść na bardziej oczywiste problemy przy użyciu typu elementu matrycowego, który ma destruktor z działaniami ubocznymi.


Trochę problemów:

  • ::operator new oczekuje wiele bajtów, ale dostarczyłeś wiele elementów.
  • W konstruktorze przypisujesz elementy, które nie zostały skonstruowane. (W C ++ 20 może to działać na trywialne typy elementów, ale nie, gdy konstruktor ma efekty uboczne). Powinieneś użyć umieszczenia nowego zamiast operatora przypisania.
  • Wersja konstruktora Brak wartości początkowej pozostawia pamięć niezainicjalizowane (i żadne obiekty utworzone), nadal musisz zadzwonić do umieszczenia nowego na każdym elemencie w tej wersji.
  • W destructor dzwonisz ~T() dla elementów, które nigdy nie miały konstruktora. Wydaje się również, że jest on wyłączony przez jeden błąd, gdy zaczynasz dzwonić przez wywołanie destructor dla elem_[size()] i nie nazywaj go dla elem[0].
  • delete elem; nazywa się size() Liczba razy, powinna być nazywana zero razy. Użyj ::operator delete poza pętlą do zapalenia pamięci. (delete Wyrażenie należy sparować z wyrażeniem new, podczas funkcji ::operator delete sparowany z funkcją ::operator new).
  • Kopiuj konstruktor, przenieś konstruktor, przypisanie kopiowania i przypisanie przenoszenia, powinny być zdefiniowane przez Ciebie i zapewnić prawidłowe zachowanie. (Które w przypadku operacji kopiowania będą wezwanie do umieszczenia nowego dla każdego elementu, jeśli zamierzasz kontynuować plan indywidualnie niszczenia każdego elementu).
2
M.M 21 listopad 2020, 22:45