Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

getBit (operator[] lesend), setBit (operator[] schreibend)

3 views
Skip to first unread message

Robert Hartmann

unread,
Jul 14, 2009, 8:48:45 AM7/14/09
to
Hallo zusammen,

Mir sind die Existenzen von bitset (aus der STL
http://www.cplusplus.com/reference/stl/bitset/ )

und dynamic_bitset (aus boost
http://www.boost.org/doc/libs/1_35_0/libs/dynamic_bitset/dynamic_bitset.html)

bekannt, beide Bitsets bieten den operator[] an:

[stl:] The function returns the value (or a reference) to the bit at
position pos.

[boost:] It provides accesses to the value of individual bits via an
operator[]

Ich produziere mir eine eigene Klasse Bitfield, mit anderen
Funktionalistäten (Wortspiegelungen, etc )

Natürlich habe ich mir zwei Methoden getBit und setBit geschieben,
siehe unten:

Den nur lesenden operator[] z.B. für die Nutzung bei

Bitfield B(5);
B.setbit(4, true);
std::cout << B[4];

habe ich auf meine getBit Methode umgeleitet:

bool Bitfield::operator[](const size_t& i) const{
if ( i>=theSize.bits) throw(rangeError());
return (getBit(i));
}


Gerne würde ich nun aber auch den schreibenden operator[]
implementieren, allerdings komme ich nicht dahinter wie das gehen soll.

Denn ich würde gerne die Möglichkeit bieten neben
B.setBit(4, true);
auch
B[4] = true;
schreiben zu können.

Es wäre nett, wenn Ihr mir mal wieder auf die Sprünge helfen könntet.

Gruß Robert


//////////////

Im folgenden sei
typedef unsigned char byte;
gegeben

sowie die Klassenvariable

byte * theField;


bool Bitfield::getBit(const size_t& bit) const {

if ((bit >= theSize.bits) || (theField == NULL))
throw rangeError();
assert(((bit < theSize.bits) && (this->theField != NULL)));

bool ret = false;

if ((bit < theSize.bits) && (this->theField != NULL)) {

size_t byteNr = bit / BITFIELD_BYTE_BITSIZE;
size_t bitNr = bit % BITFIELD_BYTE_BITSIZE;

byte& theByte = theField[byteNr];

//Verschiebe 1 nach links auf Bitnummer,
// bitweises UND mit dem Byte -> nur Position Bitnummer
// kann mit 1 belegt sein.
// Verschiebe wieder nach rechts um die gleiche Anzahl
// der Bits und vergleiche logisch mit 1 -> entweder ist
// dies der Vergleich von 1 mit 1, oder 0 mit 1
ret = (((theByte & (1 << bitNr)) >> bitNr) == 1);
}
return ret;
}

bool Bitfield::setBit(const size_t& bit, const bool& value) {
bool res = true;

if ((theField == NULL) || (theSize.bits < bit)) {
res = setSize(bit + 1); // vergrößert das Feld
}

if ((theField == NULL) || (!res))
return false;

//Bestimme aus bit -das ist die Bitnummer über das ganze
//Feld gesehen-, die Byte-Nr und die Position in dem Byte
size_t byteNr = bit / BITFIELD_BYTE_BITSIZE;
size_t bitNr = bit % BITFIELD_BYTE_BITSIZE;

byte& theByte = theField[byteNr];

if (value) { //setze Bit
//verschiebe 1 auf Bitnummer,
//dann Zuweisung des bitweisen ODERs

theByte |= (1 << bitNr);

} else { //lösche Bit
//verschiebe 1 auf Bitnummer,
//invertiere das, dann Zuweisung des bitweisen UNDs

theByte &= ~(1 << bitNr);
}
return true;
}

SG

unread,
Jul 14, 2009, 11:36:44 AM7/14/09
to
Robert Hartmann wrote:
>
> Mir sind die Existenzen von bitset (STL)
> und dynamic_bitset (Boost)

> bekannt, beide Bitsets bieten den operator[] an:

[schnipp]

> Ich produziere mir eine eigene Klasse Bitfield, mit anderen
> Funktionalistäten (Wortspiegelungen, etc )
>
> Natürlich habe ich mir zwei Methoden getBit und setBit geschieben,
> siehe unten:
>
> Den nur lesenden operator[] z.B. für die Nutzung bei

[schnipp]

> Gerne würde ich nun aber auch den schreibenden operator[]
> implementieren, allerdings komme ich nicht dahinter wie das gehen soll.
>
> Denn ich würde gerne die Möglichkeit bieten neben
> B.setBit(4, true);
> auch
> B[4] = true;
> schreiben zu können.

Du gibst einfach einen selbstdefinierten Stellvertreter einer Referenz
zurück. Ein Objekt, welches sich merkt, welches Bitfield und welches
Bit Du meinst, zu einem bool konvertierbar ist und innerhalb von
operator= das entsprechende Bit über setBit ändert. Also in etwa so:

class BitReference
{
Bitfield & bf;
unsigned index;

public:
BitReference(Bitfield & bf, unsigned index)
: bf(bf), index(index) {}

operator bool() const {return bf.getBit(index);}

BitReference& operator=(bool b)
{bf.setBit(index,b); return *this;}

BitReference& operator^=(bool b)
{bf.xorBit(index,b); return *this;}
};

Ob das jetzt der Weisheit letzer Schluss ist, weiß ich auch nicht.

> bool Bitfield::setBit(const size_t& bit, const bool& value)

Für Typen wie size_t und bool kann man sich das mit ref-to-const
sparen. Das ist eigentlich nur sinnvoll bei benutzerdefinierten Typen.

Gruß,
SG

Message has been deleted

Sebastian Waschik

unread,
Jul 14, 2009, 11:46:59 AM7/14/09
to
Hallo

Robert Hartmann <Robert_...@gmx.net> writes:
> Gerne wᅵrde ich nun aber auch den schreibenden operator[]


> implementieren, allerdings komme ich nicht dahinter wie das gehen
> soll.

du brauchst ein Proxy-Objekt, dass du vom operator[] zurᅵckgibst.

Am Ende der E-Mail ein Anfang. Den muss man dann noch zurechtbiegen,
dass auch der lesende Zugriff mᅵglich ist.

Viele Grᅵᅵe
Sebastian Waschik

#include <cassert>
#include <iostream>

class Test;

class Proxy
{
public:
Proxy(Test *const test,
const int x);
Proxy &
operator=(const char y);
private:
Test *test_;
int x_;
};

class Test
{
public:
Proxy
operator[](const int x);
void set(const int x, const char y);
int x_;
char y_;
};


Proxy::Proxy(Test *const test,
const int x) : test_(test), x_(x)
{}

Proxy &
Proxy::operator=(const char y)
{
assert(test_ != NULL);
test_->set(x_, y);
return *this;
}

Proxy
Test::operator[](const int x)
{
return Proxy(this, x);
}

void Test::set(const int x, const char y)
{
x_ = x;
y_ = y;
}

void print(const Test &test)
{
std::cout << "Test: " << test.x_ << " " << test.y_ << std::endl;
}

int main(void)
{
Test test;
test.set(0, '0');
print(test);
test[1] = '3';
print(test);

return 0;
}

James Kanze

unread,
Jul 15, 2009, 4:14:32 AM7/15/09
to
On Jul 14, 4:48 pm, Gerald Breuer <Gerald.Bre...@googlemail.com>
wrote:
> Robert Hartmann schrieb:

> > Gerne würde ich nun aber auch den schreibenden operator[]
> > implementieren, allerdings komme ich nicht dahinter wie
> > das gehen soll.

> Geht nur umständlich indem Du ein temporäres Objekt zurückgibst
> dass dann ein Proxy auf das einzelne Bit im Bitset ist - ob der
> Compiler es schafft das so gut zu optimieren, dass das bzgl. der
> Performance mit der setBit-Methode noch mithalten kann ist frag-
> lich. Ich würd mir um die ganze Sache keinen Kopf machen und
> akzeptieren, dass es für lesenden und schreibenden Zugriff zwei
> Methoden gibt.

Er hat die zwei Methoden. Am besten implementiert er das Proxy,
und benutzt es, bis der Profiler sagt anders. Es gibt immer
Zeit, das [] mit einem Aufruf von getBit bzw. setBit zu
ersetzen, falls die Stelle kritisch wird.

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James Kanze

unread,
Jul 15, 2009, 4:25:26 AM7/15/09
to
On Jul 14, 5:36 pm, SG <s.gesem...@gmail.com> wrote:
> Robert Hartmann wrote:

> Du gibst einfach einen selbstdefinierten Stellvertreter einer
> Referenz zurück. Ein Objekt, welches sich merkt, welches
> Bitfield und welches Bit Du meinst, zu einem bool
> konvertierbar ist und innerhalb von operator= das
> entsprechende Bit über setBit ändert. Also in etwa so:

Nur ein Paar kleine Hinweise (der Code ist in allgemein ganz
gut):

> class BitReference
> {
> Bitfield & bf;

Hier bevorziehe ich einen Zeiger, damit Zuweisung auch
unterstützt wird. (In der Praxis denke ich, dass die Zuweisung
nie benutzt wird. Es scheint mir aber orthogonaler, wenn sie
unterstützt wird. Geschmackssache, in einiger Weise.)

> unsigned index;

> public:
> BitReference(Bitfield & bf, unsigned index)
> : bf(bf), index(index) {}

> operator bool() const {return bf.getBit(index);}

> BitReference& operator=(bool b)

Warum nicht:
BitReference const& operator=( bool b ) const
Ein const operator= ist ein gutes Kennzeichen eines Proxys. (Nur
der besondere operator=; wenn die Zuweisung BitReference zu
BitReference unterstützt wird, soll sie die gewöhnliche Signatur
haben.)

> {bf.setBit(index,b); return *this;}
> BitReference& operator^=(bool b)
> {bf.xorBit(index,b); return *this;}

Und auch |= und &=.

> };

> Ob das jetzt der Weisheit letzer Schluss ist, weiß ich auch
> nicht.

> > bool Bitfield::setBit(const size_t& bit, const bool& value)

> Für Typen wie size_t und bool kann man sich das mit
> ref-to-const sparen. Das ist eigentlich nur sinnvoll bei
> benutzerdefinierten Typen.

Und auch nicht immer dann. Zuerst sind enum's
"benutzerdefinierte Typen". Ich denke nicht, dass du sie damit
gemeint hast. Aber auch bei anderen Typen, sowie std::complex,
könnte man oft die Referenz sparen. (Anderseits ist es eine
einfache Regel zu benutzen: const-Referenz bei Klassentypen.)

SG

unread,
Jul 15, 2009, 7:12:48 AM7/15/09
to
On 15 Jul., 10:25, James Kanze wrote:
>
> Nur ein Paar kleine Hinweise
> (der Code ist in allgemein ganz gut):
>
> On Jul 14, 5:36 pm, SG wrote:
> > class BitReference
> > {
> >   Bitfield & bf;
>
> Hier bevorziehe ich einen Zeiger, damit Zuweisung auch
> unterstützt wird. (In der Praxis denke ich, dass die Zuweisung
> nie benutzt wird. Es scheint mir aber orthogonaler, wenn sie
> unterstützt wird. Geschmackssache, in einiger Weise.)

Da sich BitReference wie eine Referenz verhalten soll und Referenzen
inhärent konstant sind, spricht nichts gegen die Speicherung einer
Referenz auf Bitfield. Die Zuweisung wird ja auch so überladen, dass
das referenzierte Bit verändert wird und nicht die Referenz selbst.

Wenn Du also nicht noch eine Funktion a la
void reseat(Bitfield& bf, unsigned index);
hinzufügen willst, ist es egal, ob Zeiger oder Referenz gespeichert
wird.

> >   unsigned index;
> > public:
> >   BitReference(Bitfield & bf, unsigned index)
> >   : bf(bf), index(index) {}
> >   operator bool() const {return bf.getBit(index);}
> >   BitReference& operator=(bool b)
>
> Warum nicht:
>     BitReference const& operator=( bool b ) const

Stimmt. Ich bin einfach nicht auf die Idee gekommen.

> > Für Typen wie size_t und bool kann man sich das mit
> > ref-to-const sparen. Das ist eigentlich nur sinnvoll bei
> > benutzerdefinierten Typen.
>
> Und auch nicht immer dann. Zuerst sind enum's
> "benutzerdefinierte Typen". Ich denke nicht, dass du sie damit
> gemeint hast. Aber auch bei anderen Typen, sowie std::complex,
> könnte man oft die Referenz sparen. (Anderseits ist es eine
> einfache Regel zu benutzen: const-Referenz bei Klassentypen.)

Ja, ich meinte Klassentypen.

Gruß,
SG

Stefan Reuther

unread,
Jul 15, 2009, 1:02:42 PM7/15/09
to
James Kanze wrote:
> On Jul 14, 5:36 pm, SG <s.gesem...@gmail.com> wrote:
>>class BitReference
>>{
>> Bitfield & bf;
>
> Hier bevorziehe ich einen Zeiger, damit Zuweisung auch
> unterst�tzt wird. (In der Praxis denke ich, dass die Zuweisung

> nie benutzt wird. Es scheint mir aber orthogonaler, wenn sie
> unterst�tzt wird. Geschmackssache, in einiger Weise.)

Warum soll man nicht z.B.
bitfeld[10] = bitfeld[20];
schreiben k�nnen? Dann h�tte man eine Zuweisung zweier Bitreferenzen.
Hier ist es sogar ein Vorteil, eine Referenz zu nehmen, weil dann der
Compiler keinen Zuweisungsoperator generiert; der w�rde eh das falsche
tun (Kopieren der Referenz statt der referierten Werte).


Stefan

James Kanze

unread,
Jul 16, 2009, 5:50:12 AM7/16/09
to
On Jul 15, 7:02 pm, Stefan Reuther <stefan.n...@arcor.de> wrote:
> James Kanze wrote:
> > On Jul 14, 5:36 pm, SG <s.gesem...@gmail.com> wrote:
> >>class BitReference
> >>{
> >> Bitfield & bf;

> > Hier bevorziehe ich einen Zeiger, damit Zuweisung auch

> > unterstützt wird. (In der Praxis denke ich, dass die Zuweisung


> > nie benutzt wird. Es scheint mir aber orthogonaler, wenn sie

> > unterstützt wird. Geschmackssache, in einiger Weise.)

> Warum soll man nicht z.B.
> bitfeld[10] = bitfeld[20];

> schreiben können? Dann hätte man eine Zuweisung zweier


> Bitreferenzen. Hier ist es sogar ein Vorteil, eine Referenz
> zu nehmen, weil dann der Compiler keinen Zuweisungsoperator

> generiert; der würde eh das falsche tun (Kopieren der Referenz
> statt der referierten Werte).

Gutes Beispiel. Das heißt, dass der von mir vorgeschlagenen
Zuweisungsoperator falsch wäre. Um so was zu unterstutzen, muss
man einen "Copy-Zuweisungsoperator" definieren, so ungefähr:

BitReference const&
BitReference::operator=(
BitReference const& other ) const
{
*this = static_cast< bool >( other ) ;
return *this ;
}

(Damit kann---oder vielleicht sogar soll---man auch dann bf als
Referenz lassen.)

Dazu: die Idee, den Zuweisungsoperator const zu machen, stammt
nicht von mir, sondern von Scott Meyer. Sie gefällt mir aber,
wiel es ausgewöhnlich genug ist, als Kennzeichen der besonderen
Semantik solcher Klassen gut zu dienen.

Robert Hartmann

unread,
Jul 17, 2009, 5:08:42 AM7/17/09
to
James Kanze schrieb:

> On Jul 15, 7:02 pm, Stefan Reuther <stefan.n...@arcor.de> wrote:
>> James Kanze wrote:
>>> On Jul 14, 5:36 pm, SG <s.gesem...@gmail.com> wrote:
>>>> class BitReference
>>>> {
>>>> Bitfield & bf;
>
>>> Hier bevorziehe ich einen Zeiger, damit Zuweisung auch
>>> unterstützt wird. (In der Praxis denke ich, dass die Zuweisung
>>> nie benutzt wird. Es scheint mir aber orthogonaler, wenn sie
>>> unterstützt wird. Geschmackssache, in einiger Weise.)
>
>> Warum soll man nicht z.B.
>> bitfeld[10] = bitfeld[20];
>> schreiben können? Dann hätte man eine Zuweisung zweier
>> Bitreferenzen. Hier ist es sogar ein Vorteil, eine Referenz
>> zu nehmen, weil dann der Compiler keinen Zuweisungsoperator
>> generiert; der würde eh das falsche tun (Kopieren der Referenz
>> statt der referierten Werte).
>
> Gutes Beispiel. Das heißt, dass der von mir vorgeschlagenen
> Zuweisungsoperator falsch wäre. Um so was zu unterstutzen, muss
> man einen "Copy-Zuweisungsoperator" definieren, so ungefähr:
>
> BitReference const&
> BitReference::operator=(
> BitReference const& other ) const
> {
> *this = static_cast< bool >( other ) ;
> return *this ;
> }
>

Warum nicht so?

BitReference::BitReference const&
BitReference::operator=( const BitReference& rhs) const
{
bf.setBit(index, rhs.bf.getBit(rhs.index));
return *this;
}

Denn die Zuweisung


>> bitfeld[10] = bitfeld[20];

soll je gerade im die Bitnummer 10 mit dem Wert an Bitnummer 20 belegen.

Gruß Robert

Robert Hartmann

unread,
Jul 17, 2009, 5:12:44 AM7/17/09
to
Hallo,

SG schrieb:


> Robert Hartmann wrote:
>> Mir sind die Existenzen von bitset (STL)
>> und dynamic_bitset (Boost)
>> bekannt, beide Bitsets bieten den operator[] an:
>
> [schnipp]
>

>> Gerne würde ich nun aber auch den schreibenden operator[]
>> implementieren, allerdings komme ich nicht dahinter wie das gehen soll.
>

> Du gibst einfach einen selbstdefinierten Stellvertreter einer Referenz
> zurück. Ein Objekt, welches sich merkt, welches Bitfield und welches
> Bit Du meinst, zu einem bool konvertierbar ist und innerhalb von
> operator= das entsprechende Bit über setBit ändert. Also in etwa so:
>
> class BitReference
> {
> Bitfield & bf;
> unsigned index;
>
> public:
> BitReference(Bitfield & bf, unsigned index)
> : bf(bf), index(index) {}
>
> operator bool() const {return bf.getBit(index);}
>
> BitReference& operator=(bool b)
> {bf.setBit(index,b); return *this;}
>
> BitReference& operator^=(bool b)
> {bf.xorBit(index,b); return *this;}
> };
>
> Ob das jetzt der Weisheit letzer Schluss ist, weiß ich auch nicht.

Danke für deine Hilfe.

Gruß Robert

Robert Hartmann

unread,
Jul 17, 2009, 5:09:42 AM7/17/09
to
Hallo,
Sebastian Waschik schrieb:

> Hallo
>
> Robert Hartmann <Robert_...@gmx.net> writes:
>> Gerne würde ich nun aber auch den schreibenden operator[]

>> implementieren, allerdings komme ich nicht dahinter wie das gehen
>> soll.
>
> du brauchst ein Proxy-Objekt, dass du vom operator[] zurückgibst.

>
> Am Ende der E-Mail ein Anfang. Den muss man dann noch zurechtbiegen,
> dass auch der lesende Zugriff möglich ist.

Danke, damit hast du mir sehr geholfen.

Gruß Robert

James Kanze

unread,
Jul 18, 2009, 6:32:27 AM7/18/09
to

> Warum nicht so?

Das kommt endgültig auf dasselbe. In der Tat würde ich
wahrscheinlich auch so schreiben. Da die Namen der Funktionnen
nicht im Posting stand, worauf ich anwortete, und ich zu faul
war, sie im früheren Posting aufzusuchen, habe ich eine
Schreibweise verwendet, die sie nicht brauchte.

> Denn die Zuweisung
> >> bitfeld[10] = bitfeld[20];

> soll je gerade im die Bitnummer 10 mit dem Wert an Bitnummer 20 belegen.

Tut's auch, beide meine Version und deine. Wenn alle Funktionnen
inline sind (häufig der Fall bei Proxy), dann würde ich sogar
erwarten, dass der Compiler in beiden Fällen genau dieselben
Machinbefehle generiert.

0 new messages