Предварительное замечание: поскольку вы не используете std :: set, я полагаю, что это упражнение, и вы не можете использовать std :: vector, который значительно облегчит управление p
Проблема (ы)
В этом коде есть некоторые противоречия, и некоторые другие ошибки, которые еще не появляются, потому что соответствующая функция-член шаблона не используется:
- Член
T** p
определен как указатель на указатель на T - В конструкторе вы выделяете массив указателей на T, который действительно даст вам указатель на указатели на T.
- Но в
add()
и remove()
вы пытаетесь перераспределить p с помощью массива T, что даст вам T*
вместо T**
. Кроме того, вы явно хотите добавить или удалить значение, а не указатель. - Но в заданном значении неясно, хотите ли вы установить единственное значение (которое предлагает
T k
в подписи) или если вы хотите установить все значения из массива (длина которого аргумент int l
предлагает). Учитывая, что имя функции имеет Values
во множественном числе, я приму второй вариант.
Решение Шаг 1. Получите его для компиляции. Но на самом деле это не сработает
Вам нужно исправить:
T *p;
и соответствующим образом адаптировать конструктор с помощью p = new T[n]
;
auto p1 = p;
Затем вам нужно изменить определение функции на:
void setValues(T k[],int l) // option 1
void setValues(T *k,int l) // or option 2
Хорошая новость заключается в том, что код будет компилироваться
Плохая новость заключается в том, что не буду делать то, что вы хотите. Кроме того, код функции и некоторые другие проблемы вызовут UB (это означает, что может произойти много плохих вещей, включая повреждение памяти, cra sh, et c ...).
Решение Шаг 2: присвоение массивов, указателей и правила 3
Этот код не соответствует ожидаемому:
void setValues(T *k, int l)
{
p = k; // OUCH !!!!!! pointer copy and not copy of the array elements
n = l;
}
В настоящее время вы делаете не копировать элементы массива, но вы заменяете указатель. Это приводит к следующим последствиям:
- Сначала вы потеряете память, так как указатель на выделенную память потерян и никогда не будет освобожден.
- секунду, вы сделаете этот указатель указателем на массив, который не был выделен с помощью
new[]
, что может сильно повредить вам, когда вы позже delete[]
этот указатель. - третий: массив, к которому ваши классовые точки могут быть удалены владельцем массива, и в этом случае вы будете использовать висячий указатель.
Таким образом, вам нужно адаптировать свой код следующим образом:
void setValues(T k[],int l) // change signature
{
if (n!=l) { // if the size is the same, we'll reuse p, if not:
delete[] p; // avoid the memory to leek
p= new T[l]; // start with a fresh memory
n = l; // define new length
}
for (int i=0; i<l; i++)
p[i]=k[i]; // copy array elements one by one
}
Другая важная проблема - это правило 3 . Это не проблема с вашим текущим main()
, но быстро станет: если вы работаете с указателями в конструкторе или деструкторе, вы должны определить конструктор копирования и оператор присваивания. Если вы этого не сделаете, вы рискуете закончить с мелкими копиями вашего набора (2 разных объекта, но с тем же указателем).
Решение Шаг 3: избавиться от оставшихся проблем
Во-первых, ваш конструктор по умолчанию оставляет p и n унифицированными. Это может быть случайное значение, которое может привести к тому, что деструктор попытается удалить то, что не было выделено. И то же самое для любой другой функции, которая предполагает, что вещи, которые приняли значения членов, были бы согласованными. Итак:
Set(){
p=nullptr;
n=0;
};
Тогда у вас есть аналогичные проблемы в add()
, которые у вас были в setValues()
с назначением указателя. Кроме того, вы go вышли за пределы, даже после переопределения: последний элемент массива p с элементом n+1
равен p[n]
, а не p [n + 1]. Я позволю вам в качестве упражнения, чтобы улучшить его.
Демо онлайн