Click to See Complete Forum and Search --> : Test this C++ code on your compiler, mine's weird ...


PolteRGeisT
03-07-2004, 08:14 PM
I'm getting a VERY bizzare error from this code. It's a simple string class, I only want to see if it's my compiler that's acting funny. thankx.



#include <iostream>
#include <string>

class String
{
public:
String();
String(const String &);
String(const String *);
String(const char *);
virtual ~String();

friend ostream &operator<< (ostream &, String &);
friend istream &operator>> (istream &, String &);

unsigned char &operator[](unsigned int);
unsigned char &operator[](unsigned int) const;

unsigned int length() const { return _length; }
const unsigned char at(unsigned int) const;

private:
unsigned char *string;
unsigned int _length;
unsigned char decoy_input;

unsigned int ctoc_assgn;
void __ctoc_assgn_lock() { ctoc_assgn = 0; }
void __ctoc_assgn_unlock() { ctoc_assgn = 1; }
unsigned int __ctoc_assgn_status() const { return ctoc_assgn; }

unsigned int strlen() const;
};

String::String()
{
string = new unsigned char;
string[0] = '\0';
_length = 0;
decoy_input = 0;

__ctoc_assgn_unlock();
}

String::String(const String &rhs)
{
this->_length = rhs.length();
for (int i=0; i < _length; ++i)
*(string + i) = rhs.at(i);
decoy_input = 0;

*(string + _length) = char (0);
__ctoc_assgn_unlock();
}

String::String(const String *rhs)
{
this->_length = rhs->length();
for (int i=0; i < _length; ++i)
*(string + i) = rhs->at(i);
decoy_input = 0;

*(string + _length) = char (0);
__ctoc_assgn_unlock();
}

String::String(const char *s)
{
int i;

for (i=0; s[i]; ++i)
*(string + i) = s[i];

decoy_input = 0;
*(string + _length) = char (0);
_length = i;
__ctoc_assgn_unlock();
}

String::~String()
{
delete [] string;
string = NULL;
_length = 0;
}

ostream &operator<<(ostream &__cout, String &rhs)
{
__cout << rhs.string;
return __cout;
}

istream &operator>>(istream &__cin, String &rhs)
{
__cin >> rhs.string;
rhs._length = rhs.strlen();

return __cin;
}

unsigned int String::strlen() const
{
int i;

for(i=0; *(string + i); ++i)
; /* Nothing */

return i;
}

const unsigned char String::at(unsigned int offset) const
{
return offset < _length ? *(string + offset) : char (0);
}

unsigned char &String::operator[](unsigned int offset)
{
if ((offset < _length) && (__ctoc_assgn_status()))
{
__ctoc_assgn_unlock();
return *(string + offset);
}

return const_cast<unsigned char &>(decoy_input);
}

unsigned char &String::operator[](unsigned int offset) const
{
if (offset < _length)
{
__ctoc_assgn_unlock();
return *(string + offset);
}

__ctoc_assgn_lock();
return const_cast<unsigned char &>(decoy_input);
}


int main()
{
String s;

cin >> s;
cout << s << endl;
cout << s.length() << endl;
cout << s.at(5) << endl;
cout << (int)s.at(1000) << endl;

s[3] = 'A';
cout << s << endl;
s[5] = s[2];
cout << s << endl;
s[2] = s[1000];
cout << s << endl;
cout << s[1000] << endl;

cin >> s;

return 0;
}



Errors are

131: Passing 'const String' as 'this' argument of void String::__ctoc_assgn_unlock() discards qualifiers.

sounds like the compiler is choking on something it's doing all by itself :rolleyes:

PolteRGeisT
03-07-2004, 08:16 PM
Hehe, devs for these forums need to disable the italics, bolds and underlines inside [ CODE ] blocks. :rolleyes:

PolteRGeisT
03-07-2004, 10:17 PM
35 people have seen this, but yet no one is able to just commpile it and tell me what happens?

c'mon.... for shame :p

madcompnerd
03-07-2004, 10:38 PM
After adding:
using namespace std;

I got these errors:
test.cpp: In member function `unsigned char& String::operator[](unsigned int)
const':
test.cpp:132: error: passing `const String' as `this' argument of `void
String::__ctoc_assgn_unlock()' discards qualifiers
test.cpp:136: error: passing `const String' as `this' argument of `void
String::__ctoc_assgn_lock()' discards qualifiers

Keep in mind the line numbers are changed because I added a line.

Wait, nvm I got it to compile. You seem to have the same function twice:
unsigned char &String::operator[](unsigned int offset)
{
if ((offset < _length) && (__ctoc_assgn_status()))
{
__ctoc_assgn_unlock();
return *(string + offset);
}

return const_cast<unsigned char &>(decoy_input);
}

/*unsigned char &String::operator[](unsigned int offset) const
{
if (offset < _length)
{
__ctoc_assgn_unlock();
return *(string + offset);
}

__ctoc_assgn_lock();
return const_cast<unsigned char &>(decoy_input);
}*/

As you can see, I commented out the const version. I dunno if that logically breaks it, but it compiled with g++ 3.3.3

PolteRGeisT
03-07-2004, 11:19 PM
Kinda figured out the problem. const qualifier on the function was what was causing the problem. so I added const qualifiers on the functions that were violating the const-ness of the entire thing. It was happening because that function was inline, so when I was changing the value of the variable inside the function, it was equivalent to doing it inside the const-qualified function. So I made the lock functions const, and made the variable mutable.


class String
{
public:
String();
String(const String &);
String(const String *);
String(const char *);
virtual ~String();

friend ostream &operator<< (ostream &, String &);
friend istream &operator>> (istream &, String &);

unsigned char &operator[](unsigned int);
unsigned char &operator[](unsigned int) const;

unsigned int length() const { return _length; }
const unsigned char at(unsigned int) const;

private:
unsigned char *string;
unsigned int _length;
unsigned char decoy_input;

// Right here
mutable unsigned int ctoc_assgn;
void __ctoc_assgn_lock() const { ctoc_assgn = 0; }
void __ctoc_assgn_unlock() const { ctoc_assgn = 1; }
unsigned int __ctoc_assgn_status() const { return ctoc_assgn; }

unsigned int strlen() const;
};



Well, i learned something new today. :) That always helps.

bwkaz
03-07-2004, 11:58 PM
"mutable"? I'm not quite familiar with that modifier...

Oh, I see. It basically lets you violate const. OK, I suppose.

Keep in mind that the const modifier, when placed after the function declaration, tells the compiler to enforce the rule that "this function cannot change any part of the class' state", which means no member variable modifications. The fact that you're taking a "lock" (or something -- it won't stand up to a multithreaded program sharing one of your strings between threads like a real lock would, but oh well) will violate that rule, which is why the compiler complained.

If you could always guarantee that any function that modified the lock variable would reset its value before exiting, then (at least in single threaded programs) you would be OK declaring it mutable, because from outside the const function, none of the object's state would have changed.

PolteRGeisT
03-08-2004, 01:11 AM
The idea behind the lock was to prevent something like this from happening:



String s = "Hello";

s[2] = s[1000];



the function/variable names "ctoc_assgn_ ..." stood for character to character assignment. It would prevent an undesireable assignment from taking place, such as the one above. However, my implementation was seriously flawed, as I thought this up at 4 in the morning. the "lock" system I came up with is pretty much garbage, as the code is executed from left to right, whereas the lock would only work (and beautifully it would have) if the code could be executed from right to left. Lesson: keep yourself well rested. :D

bwkaz
03-08-2004, 08:19 PM
Oh, OK, I get it then. :D I thought you were trying to actually lock stuff. Never mind then.

PolteRGeisT
03-12-2004, 01:11 PM
Ok ok, here it is now, it works now. :D I came back to this this morning, and figured it out.


#include <iostream>
#include <string>

class String
{
public:
String();
String(const String &);
String(const String *);
String(const char *);
virtual ~String();

friend ostream &operator<< (ostream &, String &);
friend istream &operator>> (istream &, String &);

unsigned char &operator[](unsigned int);
unsigned char &operator[](unsigned int) const;

unsigned int length() const { return _length; }
const unsigned char at(unsigned int) const;

private:
unsigned char *string;
unsigned int _length;
unsigned char *decoy_input;

mutable unsigned int ctoc_assgn;
void __ctoc_assgn_lock() const { ctoc_assgn = 0; }
void __ctoc_assgn_unlock() const { ctoc_assgn = 1; }
unsigned int __ctoc_assgn_status() const { return ctoc_assgn; }

unsigned int strlen() const;
};

String::String()
{
string = new unsigned char;
string[0] = '\0';
_length = 0;
decoy_input = new (unsigned char) (0);
}

String::String(const String &rhs)
{
this->_length = rhs.length();
for (unsigned int i=0; i < _length; ++i)
*(string + i) = rhs.at(i);
decoy_input = new (unsigned char) (0);

*(string + _length) = char (0);
}

String::String(const String *rhs)
{
this->_length = rhs->length();
for (unsigned int i=0; i < _length; ++i)
*(string + i) = rhs->at(i);
decoy_input = new (unsigned char) (0);

*(string + _length) = char (0);;
}

String::String(const char *s)
{
int i;

for (i=0; s[i]; ++i)
*(string + i) = s[i];

decoy_input = new (unsigned char) (0);
*(string + _length) = char (0);
_length = i;
}

String::~String()
{
delete [] string;
string = NULL;
_length = 0;
}

ostream &operator<<(ostream &__cout, String &rhs)
{
__cout << rhs.string;
return __cout;
}

istream &operator>>(istream &__cin, String &rhs)
{
__cin >> rhs.string;
rhs._length = rhs.strlen();

return __cin;
}

unsigned int String::strlen() const
{
int i;

for(i=0; *(string + i); ++i)
; /* Nothing */

return i;
}

const unsigned char String::at(unsigned int offset) const
{
return offset < _length ? *(string + offset) : char (0);
}

unsigned char &String::operator[](unsigned int offset)
{
if (offset < _length)
{
__ctoc_assgn_unlock(); // It's safe
*decoy_input = string[offset];
return *(string + offset);
}

__ctoc_assgn_lock(); // not safe
return const_cast<unsigned char &>(*decoy_input);
}

unsigned char &String::operator[](unsigned int offset) const
{
if ((offset < _length) && (__ctoc_assgn_status()))
{
return *(string + offset);
}

return const_cast<unsigned char &>(*decoy_input);
}


int main()
{
String s;

cin >> s;
cout << s << endl;
cout << s.length() << endl;
cout << s.at(5) << endl;
cout << (int)s.at(1000) << endl;

s[3] = 'A';
cout << s << endl;
s[5] = s[2];
cout << s << endl;
s[2] = s[1000];
cout << s << endl;
cout << (int)s[1000] << endl;

cin >> s;

return 0;
}