Битовый массив

b707
Offline
Зарегистрирован: 26.05.2017

По следам давних выступлений ЕвгенияП

Взял класс битового массива, описанный Евгением вот тут

Если кратко - это структура, содержащая упакованное битовое поле, для которой перегружен оператор индекса [] позволяющий обращатся к битовому полю как к массиву.

Немного переделал под свои нужды - упаковал в байты по 4 двух-битных значения, убрал шаблон. В принципе все получилось и работает. Но у меня в программе подобных массивов будет много, как локальных, так и глобальных. Поэтому хотелось бы создавать и удалять эти массивы динамически, чтобы иметь возможность конктролировать размер доступной памяти.

Пытаюсь переделать пример Евгения для работы с динамической памятью, написал два рабочих варианта, но оба мне не нравятся.

первый такой

#define ASIZE 15

struct CBoolArray {
	struct CunningBool {
		uint8_t& bt, mask;
		CunningBool(uint8_t& _bt, uint8_t _mask) : bt(_bt), mask(_mask) {}
		operator uint8_t(void) { return static_cast<uint8_t> ((bt >> mask) & 0x03); }
		uint8_t operator = (const uint8_t b) { return (bt = (b<<mask) | (bt & (~(0x03 << mask)))); }
	};
	uint8_t anArray[(ASIZE + 3) / 4];
	CBoolArray(void) { memset(anArray, 0, ((ASIZE + 3) / 4));}
	CunningBool operator [] (int n) { return CunningBool(anArray[n / 4], (3 -n % 4)); }
};

вроде все ОК, но при попытке создать обьект оператором new к массиву байт приходится обращаться по ссылке, что полностью обесценивает всю изящность решения с перегрузкой оператора:

CBoolArray* bitsArray = new CBoolArray;

// some function
void boo() {
	(*bitsArray)[12] = 2;
}

другой вариант - создать динамический массив для бит прямо внутри обьекта:

#define ASIZE 15

struct CBoolArray {
	struct CunningBool {
		uint8_t& bt, mask;
		CunningBool(uint8_t& _bt, uint8_t _mask) : bt(_bt), mask(_mask) {}
		operator uint8_t(void) { return static_cast<uint8_t> ((bt >> mask) & 0x03); }
		uint8_t operator = (const uint8_t b) { return (bt = (b<<mask) | (bt & (~(0x03 << mask)))); }
	};
	uint8_t* anArray;
	CBoolArray(void) { anArray = new uint8_t[(ASIZE + 3) / 4];
		               memset(anArray, 0, ((ASIZE + 3) / 4));
	}
	~CBoolArray() { delete[] anArray; }
	CunningBool operator [] (int n) { return CunningBool(anArray[n / 4], (3 -n % 4)); }
};

этот вариант тоже рабочий, но эта структура получается не совсем динамическая, да и совершенно впустую расходуется лишние 2 байта на указатель anArray

 

В чем вопрос... как бы к усам Иван Иваныча приставить бакенбарды Николая Платоныча... то есть типа совместить достоинства двух вариантов. Не могу понять, как создавать такую структуру динамически, не теряя возможности использовать перегруженный индекс напрямую.

rkit
Онлайн
Зарегистрирован: 23.11.2016

99% что всё можно выделить на стеке.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:
как бы к усам Иван Иваныча приставить бакенбарды Николая Платоныча...
Не уверен, что я понял чего нужно, но генеральное направление ...  я бы не пихал new в конструктор, а перегрузил бы оператор new (и delete тоже) для данного класса. Там была бы полная свобода и можно много чего сделать, например (чисто пример) объявить anArray нулевой или единичной длины, а сколько нужно места для него обеспечить в этом перегруженном new. Вот и совместились статически объявленный массив с динамическим куском памяти. Умеете new и delete перегружать?

b707
Offline
Зарегистрирован: 26.05.2017

Евгений, не уверен, что перегрузка new мне чем-то поможет. Ведь в любом случае после оператора new я получаю не саму структуру, а ссылку на нее. А значит опять придется обращаться к индексам так:

(*bitsArray)[12] = 2;

а хотелось бы так

bitsArray[12] = 2;

 

b707
Offline
Зарегистрирован: 26.05.2017

rkit пишет:

99% что всё можно выделить на стеке.

Программа работает до исчерпания памяти. При выделении памяти из кучи я могу контроллировать момент окончания памяти и хотя бы корректно завершить работу. При автоматическом выделении переменных на стеке - стек просто наезжает на данные и все крашится без всякой диагностики.

rkit
Онлайн
Зарегистрирован: 23.11.2016

Так надо просто статически заполнить всю память и всё.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

Евгений, не уверен, что перегрузка new мне чем-то поможет. Ведь в любом случае после оператора new я получаю не саму структуру, а ссылку на нее. А значит опять придется обращаться к индексам так:

(*bitsArray)[12] = 2;

а хотелось бы так

bitsArray[12] = 2;

Во, блин! Ну, Вы уж это ... поаккуратнее в выражениях. От Вас-то я не ожидаю, что перепутывания терминов "ссылка" и "указатель", потому и не понимаю ни хрена, что Вы пишете.  Только из примера дошло.

Т.е. речь исключительно о "синтаксическом сахаре", чтобы явно не писать разыменование? Так?

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Т.е. речь исключительно о "синтаксическом сахаре", чтобы явно не писать разыменование? Так?

да, только о нем

ЕвгенийП пишет:
От Вас-то я не ожидаю, что перепутывания терминов "ссылка" и "указатель", потому и не понимаю ни хрена, что Вы пишете.

это вы зря... :) Я хотя и понимаю разницу, но хронически путаю эти термины в разговоре :) 

Хотя в данном случае... что не так? Оператор new возвращает указатель на созданный экземпляр обьекта, который (указатель) присваивается ссылочной переменной bitsArray, через которую мы и обращаемся к нашей структуре...

 

b707
Offline
Зарегистрирован: 26.05.2017

нашел опечатку в первом сообщении

для 4х 2хбитовых значений в байте оператор индекса будет таким

CunningBool operator [] (int n) { return CunningBool(anArray[n / 4], (3 -n % 4)*2); }

 

Logik
Offline
Зарегистрирован: 05.08.2014

Та ты не переживай, ни кто там не читал даже. Ни один нормальный не полезет в ту хрень чтоб байтовые поля в массиве хранить, а ограничится чем то типа (Arr[n/4]>>(n&3)). Нет смысла усложнять примитивной. 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

А чем не устраивает стандартное :

struct bits{
unsigned bit0:1;
unsigned bit1:1;
}bit_field;

bit_field.bit0=1;

 

Очень много полей ???

b707
Offline
Зарегистрирован: 26.05.2017

Kakmyc пишет:

Очень много полей ???

от 20 до 60-ти :)

Но главное - чтобы итерировать по ним в цикле. Сейчас используется массив, где каждое значение занимает байт. Хочу уменьшить размер в 4 раза, ибо таких массивов много.

Вопрос экономии места чисто спортивный :) - это сразу чтоб не обсуждать зря, нужно мне это или нет. :)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Можно было бы ссылку сколхозить, но, зараза, битовый массив не имеет адреса.