Problem with class type in static instance of struct

  • Thread starter Robert Sturzenegger
  • Start date
R

Robert Sturzenegger

We had a strange problem in a large project with the use of a string class
in a static instance of a struct.
I managed to reproduce the exactly same problem in a very short program (see
below).
When the constant SHORT_STRING_SIZE_LIMIT is set to 0, the program works as
expected and outputs the string "+". When it is set to 7, it outputs garbage
(a part of a non-initialized storage area).
We are using gcc version 3.3 on SuSE Linux.

#include <iostream>
using namespace std;

const unsigned int SHORT_STRING_SIZE_LIMIT = 0;
//const unsigned int SHORT_STRING_SIZE_LIMIT = 7;


// String
class ----------------------------------------------------------------
class String
{
public:
String(const char* s);
friend ostream& operator<< (ostream& os, const String& sStr);

private:
char* allocate();

char m_cShortString[SHORT_STRING_SIZE_LIMIT + 1];
unsigned int m_uiCapa;
unsigned int m_uiSize;
char* m_p;
};

String::String(const char* s)
{
if (s == NULL) {
m_p = allocate();
m_p[0] = '\0';
return;
}
m_uiSize = strlen(s);
m_p = allocate();
strcpy(m_p, s);
}

char* String::allocate()
{
char* p;
if (m_uiSize <= SHORT_STRING_SIZE_LIMIT) {
m_uiCapa = SHORT_STRING_SIZE_LIMIT;
p = m_cShortString;
} else {
m_uiCapa = m_uiSize;
p = new char[m_uiCapa + 1];
}
return p;
}

ostream& operator<< (ostream& os, const String& sStr)
{
os << sStr.m_p;
return os;
}
// End of String
class ---------------------------------------------------------


struct Operators
{
String m_sOperator;
};
static Operators operators= {"+"};


int main()
{
cout << operators.m_sOperator << endl;
}
 
V

Victor Bazarov

Robert said:
We had a strange problem in a large project with the use of a string class
in a static instance of a struct.
I managed to reproduce the exactly same problem in a very short program (see
below).
When the constant SHORT_STRING_SIZE_LIMIT is set to 0, the program works as
expected and outputs the string "+". When it is set to 7, it outputs garbage
(a part of a non-initialized storage area).
We are using gcc version 3.3 on SuSE Linux.

Well, looks like a bug in the compiler. Did you use the debugger to find
out what's wrong?

V
 
A

Alan

Robert Sturzenegger said:
We had a strange problem in a large project with the use of a string class
in a static instance of a struct.
I managed to reproduce the exactly same problem in a very short program (see
below).
When the constant SHORT_STRING_SIZE_LIMIT is set to 0, the program works as
expected and outputs the string "+". When it is set to 7, it outputs garbage
(a part of a non-initialized storage area).
We are using gcc version 3.3 on SuSE Linux.

#include <iostream>
using namespace std;

const unsigned int SHORT_STRING_SIZE_LIMIT = 0;
file://const unsigned int SHORT_STRING_SIZE_LIMIT = 7;


// String
class ----------------------------------------------------------------
class String
{
public:
String(const char* s);
friend ostream& operator<< (ostream& os, const String& sStr);

private:
char* allocate();

char m_cShortString[SHORT_STRING_SIZE_LIMIT + 1];
unsigned int m_uiCapa;
unsigned int m_uiSize;
char* m_p;
};

String::String(const char* s)
{
if (s == NULL) {
m_p = allocate();
m_p[0] = '\0';
return;
}
m_uiSize = strlen(s);
m_p = allocate();
strcpy(m_p, s);
}

char* String::allocate()
{
char* p;
if (m_uiSize <= SHORT_STRING_SIZE_LIMIT) {
m_uiCapa = SHORT_STRING_SIZE_LIMIT;
p = m_cShortString;
} else {
m_uiCapa = m_uiSize;
p = new char[m_uiCapa + 1];
}
return p;
}

ostream& operator<< (ostream& os, const String& sStr)
{
os << sStr.m_p;
return os;
}
// End of String
class ---------------------------------------------------------


struct Operators
{
String m_sOperator;
};
static Operators operators= {"+"};


int main()
{
cout << operators.m_sOperator << endl;
}

I had no problems with this program using
DigitalMars (have purchased CD) in Win2K
Pro SP4 - in both cases the output is "+"

Alan
 
J

jd

Le Mon, 27 Dec 2004 17:39:24 +0100, Robert Sturzenegger a écrit :
We had a strange problem in a large project with the use of a string class
in a static instance of a struct.
I managed to reproduce the exactly same problem in a very short program (see
below).
When the constant SHORT_STRING_SIZE_LIMIT is set to 0, the program works as
expected and outputs the string "+". When it is set to 7, it outputs garbage
(a part of a non-initialized storage area).
We are using gcc version 3.3 on SuSE Linux.

#include <iostream>
using namespace std;

const unsigned int SHORT_STRING_SIZE_LIMIT = 0;
//const unsigned int SHORT_STRING_SIZE_LIMIT = 7;


// String
class ----------------------------------------------------------------
class String
{
public:
String(const char* s);
friend ostream& operator<< (ostream& os, const String& sStr);

private:
char* allocate();

char m_cShortString[SHORT_STRING_SIZE_LIMIT + 1];
unsigned int m_uiCapa;
unsigned int m_uiSize;
char* m_p;
};

String::String(const char* s)
{
if (s == NULL) {
m_p = allocate();
m_p[0] = '\0';
return;
}
m_uiSize = strlen(s);
m_p = allocate();
strcpy(m_p, s);
}

char* String::allocate()
{
char* p;
if (m_uiSize <= SHORT_STRING_SIZE_LIMIT) {
m_uiCapa = SHORT_STRING_SIZE_LIMIT;
p = m_cShortString;
} else {
m_uiCapa = m_uiSize;
p = new char[m_uiCapa + 1];
}
return p;
}

ostream& operator<< (ostream& os, const String& sStr)
{
os << sStr.m_p;
return os;
}
// End of String
class ---------------------------------------------------------


struct Operators
{
String m_sOperator;
};
static Operators operators= {"+"};


int main()
{
cout << operators.m_sOperator << endl;
}

This doesn't look a compiler error for me.
Your Operators struct simply doesn't use the constructors you have
providen for your String class.
 
R

Ron Natalie

Robert said:
We had a strange problem in a large project with the use of a string class
in a static instance of a struct.
I managed to reproduce the exactly same problem in a very short program (see
below).
When the constant SHORT_STRING_SIZE_LIMIT is set to 0, the program works as

Your class needs a copy constructor (and a assignment operator and a destructor,
and perhaps even a default constructor).

The problem is that when the limit is set to zero, the implicitly defined
copy constructor copies the pointer but since it points to memory you never
free, the thing works OK. In your case where you have the small string
support, the pointer is copied, but it points to the array of a temporary
object whose lifetime expires (and obviously gets written over).
 
M

Muk

strcpy(m_p, s);

Before you do this make sure the src string s is null terminated (\0).
In your case it looks like it is not ("+"). Now when
SHORT_STRING_SIZE_LIMIT = 7, you are copying into char
m_cShortString[8]; Since the dest array m_cShortString may not have \0
at each index, the string is basically not null terminated. This may
cause os << sStr.m_p to print vague results since it does not know the
end of the array (no \0 at end). Make sure all your arrays and strings
are null terminated, especially when using C style functions like
strcpy. When SHORT_STRING_SIZE_LIMIT = 0 you are creating new
allocation using new char[m_uiCapa + 1] and it looks like the resultant
memory had nulls in it and hence it worked.
 
V

Victor Bazarov

Muk said:
strcpy(m_p, s);

Before you do this make sure the src string s is null terminated (\0).
In your case it looks like it is not ("+"). [...]

Every string literal is null-terminated, see 2.13.4p4.
 
R

Robert Sturzenegger

Ron Natalie said:
Your class needs a copy constructor (and a assignment operator and a
destructor,
and perhaps even a default constructor).

The problem is that when the limit is set to zero, the implicitly defined
copy constructor copies the pointer but since it points to memory you
never
free, the thing works OK. In your case where you have the small string
support, the pointer is copied, but it points to the array of a temporary
object whose lifetime expires (and obviously gets written over).

What I posted, is only a small extract of the class. As a matter of course
the class does have a default ctor, several other ctors, a copy ctor and a
dtor. But these do not affect the behaviour in question and that's why I
leaved them out.
 
R

Robert Sturzenegger

jd said:
Le Mon, 27 Dec 2004 17:39:24 +0100, Robert Sturzenegger a écrit :
We had a strange problem in a large project with the use of a string class
in a static instance of a struct.
I managed to reproduce the exactly same problem in a very short program (see
below).
When the constant SHORT_STRING_SIZE_LIMIT is set to 0, the program works as
expected and outputs the string "+". When it is set to 7, it outputs garbage
(a part of a non-initialized storage area).
We are using gcc version 3.3 on SuSE Linux.

#include <iostream>
using namespace std;

const unsigned int SHORT_STRING_SIZE_LIMIT = 0;
//const unsigned int SHORT_STRING_SIZE_LIMIT = 7;


// String
class ----------------------------------------------------------------
class String
{
public:
String(const char* s);
friend ostream& operator<< (ostream& os, const String& sStr);

private:
char* allocate();

char m_cShortString[SHORT_STRING_SIZE_LIMIT + 1];
unsigned int m_uiCapa;
unsigned int m_uiSize;
char* m_p;
};

String::String(const char* s)
{
if (s == NULL) {
m_p = allocate();
m_p[0] = '\0';
return;
}
m_uiSize = strlen(s);
m_p = allocate();
strcpy(m_p, s);
}

char* String::allocate()
{
char* p;
if (m_uiSize <= SHORT_STRING_SIZE_LIMIT) {
m_uiCapa = SHORT_STRING_SIZE_LIMIT;
p = m_cShortString;
} else {
m_uiCapa = m_uiSize;
p = new char[m_uiCapa + 1];
}
return p;
}

ostream& operator<< (ostream& os, const String& sStr)
{
os << sStr.m_p;
return os;
}
// End of String
class ---------------------------------------------------------


struct Operators
{
String m_sOperator;
};
static Operators operators= {"+"};


int main()
{
cout << operators.m_sOperator << endl;
}

This doesn't look a compiler error for me.
Your Operators struct simply doesn't use the constructors you have
providen for your String class.

Yes, it does! I also tried with cout in the ctor. The ctor is run in both
cases.
 
R

Ron Natalie

Robert said:
What I posted, is only a small extract of the class. As a matter of course
the class does have a default ctor, several other ctors, a copy ctor and a
dtor. But these do not affect the behaviour in question and that's why I
leaved them out.
Perhaps you should put them back in, because it sure as hell makes the
example WRONG without them.

What does your copy constructor look like?
 
V

Victor Bazarov

Ron said:
Perhaps you should put them back in, because it sure as hell makes the
example WRONG without them.

Why is it WRONG? We're not discussing the merits of dynamic memory
allocation and the rule of three here. Is there any part to the code
presented that exhibits undefined behaviour? If yes, would you please
elaborate?
What does your copy constructor look like?

Why do you care? There is no d-tor that attempts to delete the pointer.
There is no copying taking place in this code, AFAICS. Or is there?
The question is about the code posted. It _is_ complete and is known
to exhibit the behaviour described, but only when compiled with g++
(I did check with VC++, and it worked as expected). Why does it matter
what the _other_ code looks like?
 
R

Robert Sturzenegger

Ron Natalie said:
Perhaps you should put them back in, because it sure as hell makes the
example WRONG without them.

What does your copy constructor look like?

Would you prefer to see 3786 lines of code here. As I said, this sample code
is about the minumum which is necessary, to show the behavior in question.
Every bit of code NOT shown here does NOT affect this behaviour.
In the meantime, I rather think that what is missing, are ctors and copy
ctor of the struct.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top