Скорее всего, вы копируете Bitset
куда-нибудь. Вы не определили конструктор копирования, а не оператор назначения копирования. Результатом копирования является то, что у вас есть два экземпляра, которые оба считают, что они должны освободить динамически распределенный массив, когда они закончат.
Это известно как Правило трех : если вы определяете какой-либо из деструктора, конструктора копирования или оператора копирования, скорее всего, вам нужно будет определить все три .
Теперь о вашем коде:
#include "bitset.h"
OK.
Bitset::Bitset() {
bitset = NULL;
}
(1) Вы не включили заголовок, который гарантированно определяет NULL
.
(2) вы не инициализируете элемент set_size
, поэтому проверка в операторе индекса может / будет использовать неопределенное значение с неопределенным поведением.
(3) обычно предпочитают использовать список инициализаторов, а не присваивание (это позволяет избежать, например, построения по умолчанию с последующим присваиванием).
Bitset::Bitset(const string value) {
bitset = NULL;
assign(value);
}
(4) Обычно не очень хорошая идея выражать конструкцию в терминах назначения. Вместо этого выражайте назначение с точки зрения строительства.
Bitset::~Bitset() {
if (bitset != NULL) {
delete[] bitset;
}
}
(5) Проверка для NULL
не требуется; Вы можете безопасно delete
нулевой указатель.
int Bitset::size() {
return set_size;
}
(6) Ну, ну, set_size
был участником, который не был инициализирован & hellip; Кроме того, эта функция-член должна быть const
.
void Bitset::operator= (const string value) {
assign(value);
}
(7) Оператор присваивания должен вообще возвращать ссылку на присвоенный объект. Это просто соглашение, но это то, чего ожидают пользователи вашего класса.
(8) Передайте входной аргумент по значению или по ссылке на const
. Обычно для встроенных типов выбирайте по значению, а для других типов, таких как std::string
, выберите ссылку на const
. То есть формальный аргумент должен быть лучше string const& value
.
bool Bitset::operator[] (const int index) const {
int offset;
if (index >= set_size) {
return false;
}
offset = (int) index/sizeof(unsigned char);
return (bitset[offset] >> (index - offset*sizeof(unsigned char))) & 1;
}
(9) Сначала опять неинициализированный set_size
член.
(10) Затем обратите внимание, что sizeof(unsigned char)
равно 1 по определению. Вы, вероятно, хотите использовать CHAR_BIT
из <limits.h>
здесь. Или просто используйте 8, если вы не планируете поддержку компьютеров Unisys (9-битный байт) или, возможно, цифровой сигнальный процессор Texas Instruments (16-битный байт).
void Bitset::assign(const string value) {
int i, offset;
if (bitset != NULL) {
delete[] bitset;
}
(11) Проверка для NULL
не требуется.
bitset = new unsigned char[(int) ceil(value.length()/sizeof(unsigned char))];
(12) Как уже упоминалось, sizeof(char)
равно 1 по определению.
(13) Деление имеет целочисленные аргументы и поэтому является целочисленным делением, а не делением с плавающей запятой. Предположительно, что вы хотите, это трюк (a+b-1)/b
?
for (i = 0; i < value.length(); i++) {
(14) Стиль: объявите переменную как можно ближе к ее первому использованию, насколько это практически возможно. Здесь это означает объявление счетчика цикла i
непосредственно в заголовке цикла, например: for( int i = 0, ...
.
offset = (int) i/sizeof(unsigned char);
(14) И то же самое для offset
. Но для этой переменной вы не планируете изменять ее значение, поэтому также объявите ее const
.
if (value[i] == '1') {
bitset[offset] |= (1 << (i - offset*sizeof(unsigned char)));
} else {
bitset[offset] &= ~(1 << (i - offset*sizeof(unsigned char)));
}
(15) Лучше переосмыслить эти операции смены!
}
set_size = value.length();
}
Приветствия & hth.,