Программа для преобразования класса в класс с использованием конструктора преобразования потерпела крах - PullRequest
2 голосов
/ 28 июня 2019

В приведенном ниже коде я пытаюсь преобразовать тип int * в класс vector. Но после запуска программы, программа останавливается после остановки в конструкторе преобразования, чтобы скопировать значения из int[] в vector::int *v.

Кроме того, это пример из одной из книг. Я пытался выяснить, что здесь происходит. Любые выводы будут полезны.

#include<iostream>

using namespace std;

const int size=3;

template <class T>
class vector{
    T*v;
    public:
        vector()
        {
            v=new T[size];
            for(int i=0; i<size; i++){
                cout << "A" << endl;
                v[i]=0;
            }
            cout << "vector 0-arg ctor" << endl;
        }
        vector(T *a) ///////////////////// conversion ctor for type conversion
        {
            for(int i=0; i<size; i++){
                cout << "B" << endl; 

                v[i]=a[i];////////////////// Program exits here 

            }
            cout << "vector 1-arg ctor" << endl;
        }
        T operator*(vector &y)
        {
            T sum=0;
            for(int i=0; i<size; i++){
                cout << "C" << endl;
                sum += this->v[i] * y.v[i];
            }
            return sum;
        }
};

int main(){
    int x[3]={1,2,3};
    int y[3]={4,5,6};
    vector <int> v1;
    vector <int> v2;

    v1=x; ////////////////////// Type conversion from int * -> vector
    v2=y; ////////////////////// int * -> vector

    int R=v1*v2;
    cout << "R : " << R << endl;
    return 0;
}

Выход ниже ->

A
A
A
vector 0-arg ctor
A
A
A
vector 0-arg ctor
B

1 Ответ

2 голосов
/ 28 июня 2019

В

v1=x;

Происходят две вещи:

  1. Совершенно новый временный vector построен с использованием vector(T *a). Этот временный vector никак не связан с v1
  2. Временный vector присваивается v1 с использованием сгенерированного компилятором оператора присваивания по умолчанию.

К сожалению, vector(T *a) не выделяет v и не назначает существующее хранилище для v. Так как v не указывает на действительный объект, разыменование приводит к неопределенному поведению и может сделать что угодно. На компьютере спрашивающего выглядит, как будто v[i]=a[i]; записывает в недействительную память и вызывает сбой Если бы нам всем так повезло.

Решение

Выделите немного памяти для v

vector(T *a): v(new T[size])
{
    for(int i=0; i<size; i++){
        cout << "B" << endl; 
         v[i]=a[i];
    }
    cout << "vector 1-arg ctor" << endl;
}

В качестве примера я использовал List Initializer List . Это трагически недоучено и удивительно полезно.

Не пытайтесь

vector(T *a): v(a)
{
}

хотя это выглядит очень заманчиво. Деструктор vector не может быть записан в ближайшем будущем, чтобы утечки памяти не могли сообщать статически размещенный массив x, который нельзя delete редактировать без вызова Undefined Behavior из динамического размещения, предоставляемого конструктором по умолчанию, который должен быть delete ed.

И так как тема деструкторов возникла, важно знать о Правиле Трех .

Шаг 2 из v1=x; выполняет назначение. Сгенерированный компилятором оператор присваивания по умолчанию очень прост и очень глуп. Он точно копирует то, что находится в одном vector, в другое. Если он видит указатель, он копирует адрес, а не то, на что он указывает. Что бы ни указывало на объект назначения, оно не delete ed и, вероятно, потеряно. Это оставляет вас с двумя объектами, указывающими на одну и ту же память. Изменение одного объекта теперь может изменить другой, и наступает хаос.

После этого назначения v1 v будет заменено временным vector, утечка первоначального выделения памяти v1. Хуже того, временный vector соответствует названию и быстро выходит из области видимости. Как только у vector будет функционирующий деструктор, временное устройство возьмет его с собой v, и, поскольку v1 и временное теперь указываются в том же распределении памяти, v1 'v остается указанным в неверной памяти.

Требуется оператор присваивания для устранения этой путаницы. См. Copy и Swap Idiom для очень простого, очень безопасного способа написать оператор присваивания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...