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

Bug in my C++ program seems really strange. (Update on debugging progress)

5 views
Skip to first unread message

mike3

unread,
Aug 31, 2007, 9:48:39 PM8/31/07
to
Hi.

I seem to have made some progress on finding that bug in my program. I
deactivated everything in the bignum package that was used except for
the returning of BigFloat objects. I even crippled all the
constructors. So now all the operations and constructors that were
used do is just return BigFloats but no memory is actually accessed at
any point, nor is any allocated. However, when I reenable those parts
of the constructor that allocate memory, and _then_ enable the part of
the _de_structor that _frees_ the memory, the bug appears. It only
seems when I go to allocate the "digits" buffer with (in constructor)

digits = new DIGIT32[length];

and free with (in destructor)

delete digits;

or:

(allocate in constructor) digits = (DIGIT32
*)malloc(length*sizeof(DIGIT32));

(free in destructor) free(digits);

When I don't call free or delete, though, the crash does not appear.
But it does not seem to be something needing the memory and then
accessing it as I tried it with none allocated in the first place and
"digits" set to a dummy pointer, and there was no bug nor any attempt
to access the memory as that would crash the program. It only happens
when you allocate memory in the constructor and free it in the
destructor. Freeing it immediately after allocation, in the
constructor, does not result in the crash bug.

What gives, anyway?

mike3

unread,
Aug 31, 2007, 9:49:30 PM8/31/07
to

mike3

unread,
Aug 31, 2007, 10:04:02 PM8/31/07
to
Ooops! Sorry about the double posting. Darn,
Google crashed...

Alf P. Steinbach

unread,
Aug 31, 2007, 10:52:30 PM8/31/07
to
* mike3:

This seems to be a classic case of violation of the rule of three. Rule
of three: if you have a destructor or an assignment operator or a copy
constructor, then you should in general have all three.

What happens with an RO3 violation is that an object is copied including
its pointers, in the raw, and then two or more objects all deallocate
via the same pointer values, so that something is multiply deallocated.

From another point of view an RO3 violation is most often a classic
case of evil premature optimization, usually going down to the lowest
possible level of abstraction instead of more sensibly using the highest
level available (like the standard C++ library), which provides the
required safe copying functionality automatically.

If I understand it correctly, what you have is C level code, let's call
that level 0, like

typedef ... DIGIT32; // Note: reserve all uppercase for macros!

struct MyClass
{
DIGIT32* myDigits;
int myLength;

MyClass( int aLength )
{
myLength = aLength;
digits = (DIGIT32)(malloc(...);
}

~MyClass()
{
free( myDigits );
}
};

There are number of abstraction levels between that hazardious C style
code and proper C++ code.

I'll discuss this in order, how to move from C style to C++.

Level 1, simply packaging that code using C++ constructs. A kind of
word for word translation from C to C++. This does not fix the RO3
violation, but paves the way for fixing it:

typedef ... Digit32;

class MyClass
{
private:
Digit32* myDigits;
int myLength;

public:
MyClass( int aLength )
: myLength( aLength )
, myDigits( new Digit32[aLength] )
{}

~MyClass() { delete[] myDigits; }
};

This does the same as the C-style code, but without casts and generally
in a bit more safe way, although as mentioned not fixing RO3 violation.

Level 2, implementing proper copying, that is, fixing that violation:

typedef ... Digit32;

class MyClass
{
private:
Digit32* myDigits;
int myLength;

public:
MyClass( int aLength )
: myLength( aLength )
, myDigits( new Digit32[aLength] )
{}

MyClass( MyClass const& other )
: myLength( other.myLength )
, myDigits( new Digit32[other.myLength] )
{
Digit32 const* const srcDigits = other.myDigits;
std::copy( srcDigits, srcDigits+myLength, myDigits );
}

~MyClass() { delete[] myDigits; }

void swap( MyClass& other )
{
std::swap( myDigits, other.myDigits );
std::swap( myLength, other.myLength );
}

MyClass& operator=( MyClass other )
{
swap( other );
return *this;
}
};

Now that became slightly complicated, so on to level 3, using standard
containers that implement the copying for you:

typedef ... Digit32;

class MyClass
{
private:
std::vector<Digit32> myDigits;
public:
MyClass( int aLength ): myDigits( aLength ) {}
};

Simple, yes?

Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Gianni Mariani

unread,
Aug 31, 2007, 10:51:48 PM8/31/07
to
mike3 wrote:
...
> What gives, anyway?

Something in your code is trashing memory.

I'd suggest running valgrind, efence or bounds-checker.

mike3

unread,
Aug 31, 2007, 11:46:35 PM8/31/07
to

That does not happen. See, I had in there a full copy constructor
that copied no pointers at all. Nor does the assignment operator
or any of those things copy _pointers_. They all copy _data_,
and only data. But in this case there isn't _anything_ going
on except blanks being constructed and passed around, as I've
stripped it down.

> From another point of view an RO3 violation is most often a classic
> case of evil premature optimization, usually going down to the lowest
> possible level of abstraction instead of more sensibly using the highest
> level available (like the standard C++ library), which provides the
> required safe copying functionality automatically.
>

Actually there was no evil optimization.

That is more like what I have now, at this moment.
It is failing whenever delete[] digits is present.
When that is absent from the destructor and the
memory is allowed to "persist" (NOT something I'd
do in the real live program but something I'm doing
as part of my testing), the bug seems to go away.

> This does the same as the C-style code, but without casts and generally
> in a bit more safe way, although as mentioned not fixing RO3 violation.
>
> Level 2, implementing proper copying, that is, fixing that violation:
>

The failure occurs even when the copy routines have
been specifically disabled and don't do a thing.

Simple, yes. Can you access a "vector" like you do a
regular array? Ie. is myDigits[0] = 0xFFFFFFFF
something okay to do?

> Cheers, & hth.,
>
> - Alf
>
> --
> A: Because it messes up the order in which people normally read text.
> Q: Why is it such a bad thing?
> A: Top-posting.

> Q: What is the most annoying thing on usenet and in e-mail?- Hide quoted text -
>
> - Show quoted text -


mike3

unread,
Aug 31, 2007, 11:47:37 PM8/31/07
to
On Aug 31, 8:51 pm, Gianni Mariani <gi3nos...@mariani.ws> wrote:
> mike3 wrote:
>
> ...
>
> > What gives, anyway?
>
> Something in your code is trashing memory.
>

I've pretty much guessed that at this point but
I have no idea what it could possibly be.

> I'd suggest running valgrind, efence or bounds-checker.

Does that stuff work under Windows?

Alf P. Steinbach

unread,
Sep 1, 2007, 12:32:07 AM9/1/07
to
* mike3:

>>
>
> Actually there was no evil optimization.

Using malloc and free is, just to give one example.

[snip]


>
> Can you access a "vector" like you do a
> regular array? Ie. is myDigits[0] = 0xFFFFFFFF
> something okay to do?

Yes.

Although you'll most probably be better off using the 'at' member
function, because it checks whether the argument is a valid index.

Cheers, & hth.,

- Alf


PS: Please don't quote signatures.

mike3

unread,
Sep 1, 2007, 12:50:02 AM9/1/07
to
On Aug 31, 10:32 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * mike3:
>
>
>
> > Actually there was no evil optimization.
>
> Using malloc and free is, just to give one example.
>
> [snip]
>

But it's still buggered with new and delete, too. I
only went back to malloc and free to see if that
would resolve the bug, and it didn't.

By the way, if you need it, you can get the source
code to a "stripped down" version of the program
here:

http://www.mediafire.com/?cfmzd1y3yij


>
>
> > Can you access a "vector" like you do a
> > regular array? Ie. is myDigits[0] = 0xFFFFFFFF
> > something okay to do?
>
> Yes.
>
> Although you'll most probably be better off using the 'at' member
> function, because it checks whether the argument is a valid index.
>

Alright.

Gianni Mariani

unread,
Sep 1, 2007, 2:07:46 AM9/1/07
to

bounds checker does - I used it once - lots of false positives.
Valgrind on Linux works like a charm.

Gianni Mariani

unread,
Sep 1, 2007, 2:23:44 AM9/1/07
to
mike3 wrote:
> On Aug 31, 10:32 pm, "Alf P. Steinbach" <al...@start.no> wrote:
...
> http://www.mediafire.com/?cfmzd1y3yij

How does one build all that ?

Alf P. Steinbach

unread,
Sep 1, 2007, 2:57:46 AM9/1/07
to
* Gianni Mariani:

Changes to make it /compile/:


fracalg\computefrac.cpp(371):#if 0 //APS

fracalg\computefrac.cpp(378):#endif //APS

fracalg\computefrac.cpp(393):#if 0 //APS

fracalg\computefrac.cpp(396):#else //APS

fracalg\computefrac.cpp(397): err = FG3DError(FG3D_INVALID_FRACTAL_TYPE,
FractalType); //APS

fracalg\computefrac.cpp(398):#endif //APS
render\render.cpp(51): //APS MessageBox(NULL, TEXT("Zorg."),
TEXT(""), MB_OK);

render\render.cpp(69): //APS MessageBox(NULL, TEXT("Borg."),
TEXT(""), MB_OK);

win32\CMainWnd.cpp(52): wcx.hCursor = LoadCursor(0,
IDC_ARROW); //APS LoadCursor((HANDLE)NULL, IDC_ARROW); /* cursor */

win32\fg3dImageWindow.cpp(34): wcx.hCursor =
LoadCursor(0,IDC_ARROW); //APS //LoadCursor((HANDLE)NULL, IDC_ARROW); /*
cursor */

win32\fg3dNewImageWzrd.cpp(18)://APS HWND gTmp;

win32\fg3dNewImageWzrd.cpp(32)://APS gTmp = hwndTmp;

main.h(108)://APS extern HWND gTmp;

fracgen3d.cpp(79):// APS


Plus, the WinMain function must be changed to something like


int WINAPI WinMain(HINSTANCE TheInstance, HINSTANCE LastInstance,
LPSTR lpszCmdLine, int iCmdShow)
{
__try
{
return cppWinMain( TheInstance, LastInstance, lpszCmdLine,
iCmdShow );
}
__except(TRUE)
{
TCHAR szBuf[256];
StringCchPrintf(szBuf, 256, TEXT("EXCEPTION %08lX"),
GetExceptionCode());
OutputDebugString(szBuf);
return 0;
}
}


where cppWinMain contains the original code for that __try.

It's funny (is that the right word?) when the code contains C style
casts that makes it not compile, when all that's needed is to remove
those casts...

Having done all the above the program crashes on using an invalid
pointer txtrptr in [render.cpp] at line 62, which is due to using an
uninitialized member "d3dlr" (presumably there should have been an
earlier call to FractalImage::LockRectangle, but no such).

Yes, I must be very bored to do such a thing! :-)

Cheers, & hth. (although I didn't look at the silly bignum class,
whatever its fault is, it may just be corrupted memory in general),

- Alf

BobR

unread,
Sep 1, 2007, 12:17:41 PM9/1/07
to

mike3 <mike...@yahoo.com> wrote in message...

>
> digits = new DIGIT32[length];
>
> and free with (in destructor)
>
// > delete digits;

delete [] digits;

If you 'new', you 'delete'.
If you 'new[]', you 'delete[]'.

--
Bob R
POVrookie


mike3

unread,
Sep 1, 2007, 2:37:21 PM9/1/07
to
On Sep 1, 12:57 am, "Alf P. Steinbach" <al...@start.no> wrote:
> * Gianni Mariani:
>
> > mike3 wrote:
> >> On Aug 31, 10:32 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> > ...
> >>http://www.mediafire.com/?cfmzd1y3yij
>
> > How does one build all that ?
>
> Changes to make it /compile/:
>
> fracalg\computefrac.cpp(371):#if 0 //APS
>
> fracalg\computefrac.cpp(378):#endif //APS
>
> fracalg\computefrac.cpp(393):#if 0 //APS
>
> fracalg\computefrac.cpp(396):#else //APS
>

Excuse me, why all this? Those were commented
out for debugging purposes to help minimalize
the code.

> fracalg\computefrac.cpp(397): err = FG3DError(FG3D_INVALID_FRACTAL_TYPE,
> FractalType); //APS
>
> fracalg\computefrac.cpp(398):#endif //APS

This too.

> render\render.cpp(51): //APS MessageBox(NULL, TEXT("Zorg."),
> TEXT(""), MB_OK);
>
> render\render.cpp(69): //APS MessageBox(NULL, TEXT("Borg."),
> TEXT(""), MB_OK);
>

Why couldn't it compile with those in?

I must be using a really crappy C++ compiler then as
it allows that stuff.

So then it casts it automatically, you don't need all
that C-style stuff, then? Darn I'm too paranoid.

> Having done all the above the program crashes on using an invalid
> pointer txtrptr in [render.cpp] at line 62, which is due to using an
> uninitialized member "d3dlr" (presumably there should have been an
> earlier call to FractalImage::LockRectangle, but no such).
>

That is uninitialized? It calls LockRectangle() right
in there @ line 46.

> Yes, I must be very bored to do such a thing! :-)
>
> Cheers, & hth. (although I didn't look at the silly bignum class,
> whatever its fault is, it may just be corrupted memory in general),
>

I've had a bear of a time trying to track it down.

mike3

unread,
Sep 1, 2007, 2:37:36 PM9/1/07
to
On Sep 1, 10:17 am, "BobR" <removeBadB...@worldnet.att.net> wrote:
> mike3 <mike4...@yahoo.com> wrote in message...

>
> > digits = new DIGIT32[length];
>
> > and free with (in destructor)
>
> // > delete digits;
>
> delete [] digits;
>
> If you 'new', you 'delete'.
> If you 'new[]', you 'delete[]'.
>

Tried that, still crashes!

> --
> Bob R
> POVrookie


mike3

unread,
Sep 1, 2007, 2:44:21 PM9/1/07
to
On Sep 1, 12:07 am, Gianni Mariani <gi3nos...@mariani.ws> wrote:
> mike3 wrote:
> > On Aug 31, 8:51 pm, Gianni Mariani <gi3nos...@mariani.ws> wrote:
> >> mike3 wrote:
>
> >> ...
>
> >>> What gives, anyway?
> >> Something in your code is trashing memory.
>
> > I've pretty much guessed that at this point but
> > I have no idea what it could possibly be.
>
> >> I'd suggest running valgrind, efence or bounds-checker.
>
> > Does that stuff work under Windows?
>
> bounds checker does - I used it once - lots of false positives.

Oof, that doesn't sound too good.

BobR

unread,
Sep 1, 2007, 4:45:53 PM9/1/07
to

mike3 <mike...@yahoo.com> wrote in message...
> On Sep 1, 12:57 am, "Alf P. Steinbach" <al...@start.no> wrote:
> >
> > Changes to make it /compile/:
> >
> > fracalg\computefrac.cpp(371):#if 0 file://APS
> > fracalg\computefrac.cpp(378):#endif file://APS
> > fracalg\computefrac.cpp(393):#if 0 file://APS
> > fracalg\computefrac.cpp(396):#else file://APS

>
> Excuse me, why all this? Those were commented
> out for debugging purposes to help minimalize
> the code.

Then they should have been removed for posting. I would be pissed if I spent
good money to download it with my slow dial-up.

>
> > render\render.cpp(51): file://APS MessageBox(NULL, TEXT("Zorg."),
> > TEXT(""), MB_OK);
> > render\render.cpp(69): file://APS MessageBox(NULL, TEXT("Borg."),


> > TEXT(""), MB_OK);
>
> Why couldn't it compile with those in?

It's windows code. GNU don't play that!

>
> > win32\CMainWnd.cpp(52): wcx.hCursor = LoadCursor(0,

> > IDC_ARROW); file://APS LoadCursor((HANDLE)NULL, IDC_ARROW); /* cursor */
> >
> > win32\fg3dImageWindow.cpp(34): wcx.hCursor =
> > LoadCursor(0,IDC_ARROW); file://APS file://LoadCursor((HANDLE)NULL,


IDC_ARROW); /*
> > cursor */
> >
> > win32\fg3dNewImageWzrd.cpp(18)://APS HWND gTmp;
> > win32\fg3dNewImageWzrd.cpp(32)://APS gTmp = hwndTmp;
> > main.h(108)://APS extern HWND gTmp;
> > fracgen3d.cpp(79):// APS
> >
> > Plus, the WinMain function must be changed to something like
> >
> > int WINAPI WinMain(HINSTANCE TheInstance, HINSTANCE LastInstance,
> > LPSTR lpszCmdLine, int iCmdShow){
> > __try{
> > return cppWinMain( TheInstance, LastInstance, lpszCmdLine,
> > iCmdShow );
> > }
> > __except(TRUE){
> > TCHAR szBuf[256];
> > StringCchPrintf(szBuf, 256, TEXT("EXCEPTION %08lX"),
> > GetExceptionCode());
> > OutputDebugString(szBuf);
> > return 0;
> > }
> > }
> >
> > where cppWinMain contains the original code for that __try.
> >
> > It's funny (is that the right word?) when the code contains C style
> > casts that makes it not compile, when all that's needed is to remove
> > those casts...
>
> I must be using a really crappy C++ compiler then as
> it allows that stuff.

Then set it up for standard compliance, and raise the warning levels.

>
> So then it casts it automatically, you don't need all
> that C-style stuff, then? Darn I'm too paranoid.

If you must, use the C++ casts so you get the proper warnings/errors.

>
> > Having done all the above the program crashes on using an invalid
> > pointer txtrptr in [render.cpp] at line 62, which is due to using an
> > uninitialized member "d3dlr" (presumably there should have been an
> > earlier call to FractalImage::LockRectangle, but no such).
>
> That is uninitialized? It calls LockRectangle() right
> in there @ line 46.

Did you check whether the pointer is valid during/after the 'call'?

If nothing else, try something like:
std::cout<<"pointer addr="<<pointer<<" calling:"<<*pointer;

If the pointer is invalid, that should cause a 'crash'. Then you'll know.

I've run into trouble in my own "spaghetti" code. Now days I separate the
GUI interface, C++ interface, and the work-horse code. Makes it much easier
to track problems, port to another OS, etc.. ( even wxWidgets needs some
'tweaking' between windows and GNU (GTK), but the underlying std C++ code
stays the same.)

--
Bob R
POVrookie


mike3

unread,
Sep 1, 2007, 5:17:55 PM9/1/07
to
On Sep 1, 2:45 pm, "BobR" <removeBadB...@worldnet.att.net> wrote:
> mike3 <mike4...@yahoo.com> wrote in message...

> > On Sep 1, 12:57 am, "Alf P. Steinbach" <al...@start.no> wrote:
>
> > > Changes to make it /compile/:
>
> > > fracalg\computefrac.cpp(371):#if 0 file://APS
> > > fracalg\computefrac.cpp(378):#endif file://APS
> > > fracalg\computefrac.cpp(393):#if 0 file://APS
> > > fracalg\computefrac.cpp(396):#else file://APS
>
> > Excuse me, why all this? Those were commented
> > out for debugging purposes to help minimalize
> > the code.
>
> Then they should have been removed for posting. I would be pissed if I spent
> good money to download it with my slow dial-up.
>

Looking again at the changes he posted I'm not sure
what they were supposed to do, if they were to
remove undefines or add them in. I looked at my
package and there doesn't seem to be anything
commented out or otherwise removed. Perhaps he
could explain the problem that this was supposed
to remedy? I'm not sure what is going on there
now.

<snip>


> > Why couldn't it compile with those in?
>
> It's windows code. GNU don't play that!
>

He was using GNU compilers? I thought there
were versions of the GNU compilers for Windows.
If his compiler, GNU or otherwise, was unable
to support Windows he couldn't have run the
program as the whole "main" thing, "wnd" stuff
was all Windows. I'm guessing his compiler did
support Windows since he was able to run it
without modifications _that_ extensive.

<snip>


> > I must be using a really crappy C++ compiler then as
> > it allows that stuff.
>
> Then set it up for standard compliance, and raise the warning levels.
>

What compiler do you use, by the way? I've got a
version of the GNU compilers on my system too,
and I could feed the non-Windows stuff through
it. If you're using GNU compilers (as I've
assumed from your "GNU don't play that!" comment),
could you explain how you do this (the "set it up
for standard compilance" part. I already know
how to raise the warning level.).

>
>
> > So then it casts it automatically, you don't need all
> > that C-style stuff, then? Darn I'm too paranoid.
>
> If you must, use the C++ casts so you get the proper warnings/errors.
>

Well I've been converting my main program to use
these.

>
>
> > > Having done all the above the program crashes on using an invalid
> > > pointer txtrptr in [render.cpp] at line 62, which is due to using an
> > > uninitialized member "d3dlr" (presumably there should have been an
> > > earlier call to FractalImage::LockRectangle, but no such).
>
> > That is uninitialized? It calls LockRectangle() right
> > in there @ line 46.
>
> Did you check whether the pointer is valid during/after the 'call'?
>

Why the scare quotes around "call", anyway?

Alf P. Steinbach

unread,
Sep 1, 2007, 5:38:08 PM9/1/07
to
* mike3:

> On Sep 1, 12:57 am, "Alf P. Steinbach" <al...@start.no> wrote:
>> * Gianni Mariani:
>>
>>> mike3 wrote:
>>>> On Aug 31, 10:32 pm, "Alf P. Steinbach" <al...@start.no> wrote:
>>> ...
>>>> http://www.mediafire.com/?cfmzd1y3yij
>>> How does one build all that ?
>> Changes to make it /compile/:
>>
>> fracalg\computefrac.cpp(371):#if 0 //APS
>>
>> fracalg\computefrac.cpp(378):#endif //APS
>>
>> fracalg\computefrac.cpp(393):#if 0 //APS
>>
>> fracalg\computefrac.cpp(396):#else //APS
>>
>
> Excuse me, why all this? Those were commented
> out for debugging purposes to help minimalize
> the code.

I don't remember but I think you can figure it out. :-)


>> fracalg\computefrac.cpp(397): err = FG3DError(FG3D_INVALID_FRACTAL_TYPE,
>> FractalType); //APS
>>
>> fracalg\computefrac.cpp(398):#endif //APS
>
> This too.

This I think I remember. You called some fractal computation functions
that you didn't supply.


>> render\render.cpp(51): //APS MessageBox(NULL, TEXT("Zorg."),
>> TEXT(""), MB_OK);
>>
>> render\render.cpp(69): //APS MessageBox(NULL, TEXT("Borg."),
>> TEXT(""), MB_OK);
>>
>
> Why couldn't it compile with those in?

Would compile but would not work, just silent termination. Don't set up
message loops in rendering. Btw., that has nothing to do with C++.

Yes. In addition it seem you're not using your compiler in the best
possible way. After upgrading to a better compiler, turn on all
standard-conformance and all warnings, make the thing compile cleanly.


> So then it casts it automatically, you don't need all
> that C-style stuff, then? Darn I'm too paranoid.

No, it's good to be paranoid in coding. But introducing casts is the
opposite of being paranoid: you're turning off all checks!

To be sufficiently paranoid you need to do the /opposite/: no casts.

Or at least as few as possible, and none in high-level code.


>> Having done all the above the program crashes on using an invalid
>> pointer txtrptr in [render.cpp] at line 62, which is due to using an
>> uninitialized member "d3dlr" (presumably there should have been an
>> earlier call to FractalImage::LockRectangle, but no such).
>>
>
> That is uninitialized? It calls LockRectangle() right
> in there @ line 46.

I'm just reporting what it did. There was no actual call to that
function at run-time, before the crash. As to why that should happen,
well. :-)


>> Yes, I must be very bored to do such a thing! :-)
>>
>> Cheers, & hth. (although I didn't look at the silly bignum class,
>> whatever its fault is, it may just be corrupted memory in general),
>>
>
> I've had a bear of a time trying to track it down.

General advice: in lots of places in the code there are checks whether
something is initialized or not.

If you instead make sure that constructors either initialize completely
and successfully, or else throw exceptions, you will only have properly
initialized objects around, and so you won't have to do that complicated
and leg-breaking dance.

Where it seems that you absolutely need some halfway initialized state,
like, calling a common Init function, consider replacing that Init
function with a proper constructor in a private base class (of course
this most often indicates a design issue, but better with a technical
fix than having that halfway initialized state causing general mess).

Cheers, & hth.,

mike3

unread,
Sep 1, 2007, 6:25:57 PM9/1/07
to
On Sep 1, 3:38 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * mike3:
>
>
>
>
>
> > On Sep 1, 12:57 am, "Alf P. Steinbach" <al...@start.no> wrote:
> >> * Gianni Mariani:
>
> >>> mike3 wrote:
> >>>> On Aug 31, 10:32 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> >>> ...
> >>>>http://www.mediafire.com/?cfmzd1y3yij
> >>> How does one build all that ?
> >> Changes to make it /compile/:
>
> >> fracalg\computefrac.cpp(371):#if 0 //APS
>
> >> fracalg\computefrac.cpp(378):#endif //APS
>
> >> fracalg\computefrac.cpp(393):#if 0 //APS
>
> >> fracalg\computefrac.cpp(396):#else //APS
>
> > Excuse me, why all this? Those were commented
> > out for debugging purposes to help minimalize
> > the code.
>
> I don't remember but I think you can figure it out. :-)
>
> >> fracalg\computefrac.cpp(397): err = FG3DError(FG3D_INVALID_FRACTAL_TYPE,
> >> FractalType); //APS
>
> >> fracalg\computefrac.cpp(398):#endif //APS
>
> > This too.
>
> This I think I remember. You called some fractal computation functions
> that you didn't supply.
>

Darnit, I forgot to remove the references in
stripping. I'm updating my main program, by
the way, to take into account all these
things you've mentioned.

> >> render\render.cpp(51): //APS MessageBox(NULL, TEXT("Zorg."),
> >> TEXT(""), MB_OK);
>
> >> render\render.cpp(69): //APS MessageBox(NULL, TEXT("Borg."),
> >> TEXT(""), MB_OK);
>
> > Why couldn't it compile with those in?
>
> Would compile but would not work, just silent termination. Don't set up
> message loops in rendering. Btw., that has nothing to do with C++.
>

OK.

What would be a better compiler, by the way? I've only
got this one since I didn't have to pay money for it
and I do not have a lot of money.

> > So then it casts it automatically, you don't need all
> > that C-style stuff, then? Darn I'm too paranoid.
>
> No, it's good to be paranoid in coding. But introducing casts is the
> opposite of being paranoid: you're turning off all checks!
>
> To be sufficiently paranoid you need to do the /opposite/: no casts.
>
> Or at least as few as possible, and none in high-level code.
>

OK.

Then I'd be curious to know. Does this require a cast,
to get the value of the pointer for our error information?:

FG3DError SomeRoutine(BigFloat *a)
{
FG3DError err;

<blah blah blah>

if(<some operation on "a" failed>)
return(FG3DError(<Error code>, a)); <--- here
else
return(FG3DError(FG3D_SUCCESS));
}

And this?

long MultiplyShorts(short b, short c)
{
long a;

a = b*c;

return(a);
}

Will this give the full "long" result or
do I need to typecast b and c to "short"?
And will it do that on all compilers (in case
I change my choice of compiler in the future),
ie. is that "standard" behavior? Especially
that last part right there -- is it _standard_
for a = b*c to be the full long product of b
and c, or not? I need that long product!

or this?:

double DivideInts(int a, int b)
{
double t;

t = a/b;

return(t);
}

Does that give a full floating-point double-
precision quotient of a and b or an integer one?
By the _C++ standard_, remember. See, in all
three of these situations I've used a cast, and
it is these situations that account for the vast
majority of my cast use.

> >> Having done all the above the program crashes on using an invalid
> >> pointer txtrptr in [render.cpp] at line 62, which is due to using an
> >> uninitialized member "d3dlr" (presumably there should have been an
> >> earlier call to FractalImage::LockRectangle, but no such).
>
> > That is uninitialized? It calls LockRectangle() right
> > in there @ line 46.
>
> I'm just reporting what it did. There was no actual call to that
> function at run-time, before the crash. As to why that should happen,
> well. :-)
>

Uh oh...

Why wouldn't it call? That does not make any sense! It
calls on my machine.

> >> Yes, I must be very bored to do such a thing! :-)
>
> >> Cheers, & hth. (although I didn't look at the silly bignum class,
> >> whatever its fault is, it may just be corrupted memory in general),
>
> > I've had a bear of a time trying to track it down.
>
> General advice: in lots of places in the code there are checks whether
> something is initialized or not.
>

I'm paranoid.

> If you instead make sure that constructors either initialize completely
> and successfully, or else throw exceptions, you will only have properly
> initialized objects around, and so you won't have to do that complicated
> and leg-breaking dance.
>

The constructors do throw exceptions if they cannot initialize
something
completely and successfully. So it would be OK to remove all
initialization
checks except the exception throwing, then?

> Where it seems that you absolutely need some halfway initialized state,
> like, calling a common Init function, consider replacing that Init
> function with a proper constructor in a private base class (of course
> this most often indicates a design issue, but better with a technical
> fix than having that halfway initialized state causing general mess).
>

The reason I chose the "Init" function in the bignum "BigFloat"
thing was beacuse I would have to repeat the same memory-allocation
code in each constructor so I wanted to save some space. I heard
repetition of code wasn't a good idea, so I just encapuslated
that code which would be identical between the constructors
in a nice, easy-to-service routine called "Init". "Init"
is never called anywhere else except in constructors for
BigFloat (it's a "private" member function as well.). At no
point do I need a "half-initialized" something. Whenever I
need it initialized in a certain way, I just make another
constructor for that (For example there's a constructor that
will initialize a BigFloat to a given "double" float.).

That's all I have that for, to make maintenance easier and
to avoid repetition.

Alf P. Steinbach

unread,
Sep 1, 2007, 7:06:21 PM9/1/07
to
* mike3:

>
> What would be a better compiler, by the way? I've only
> got this one since I didn't have to pay money for it
> and I do not have a lot of money.

It seems you forgot to state which compiler you're using.

However, seeing as this is Windows programming, Visual C++ 8.0 is fairly
good and gratis. Including an IDE, which, unfortunately, is crappy.

[snip]


> Then I'd be curious to know. Does this require a cast,
> to get the value of the pointer for our error information?:
>
> FG3DError SomeRoutine(BigFloat *a)
> {
> FG3DError err;
>
> <blah blah blah>
>
> if(<some operation on "a" failed>)
> return(FG3DError(<Error code>, a)); <--- here
> else
> return(FG3DError(FG3D_SUCCESS));
> }

Do something like

void someRoutine( BigFloat const& a )
{
// some operation on "a"
}

If "some operation" fails it will throw an exception.

Notice how extremely much simpler this is, in addition to be much more safe.


> And this?
>
> long MultiplyShorts(short b, short c)
> {
> long a;
>
> a = b*c;
>
> return(a);
> }

Here you need conversion:

inline long productOf( short a, short b )
{
long aLong const = a;
return aLong*b;
}

or

inline long productOf( short a, short b )
{
return (a+0L)*b;
}

Since this function is evidently intended to be used in expressions, the
name has been changed to indicate the result rather than the operation
(like, instead of "computeSin", just "sin").


> Will this give the full "long" result

No, in the code you showed the arguments would be promoted to int, the
computation done as int, and only then the result converted to long.


> or
> do I need to typecast b and c to "short"?

?


[snip]


> double DivideInts(int a, int b)
> {
> double t;
>
> t = a/b;
>
> return(t);
> }
>
> Does that give a full floating-point double-
> precision quotient of a and b or an integer one?

Integer.


> By the _C++ standard_, remember. See, in all
> three of these situations I've used a cast, and
> it is these situations that account for the vast
> majority of my cast use.

No need to use casts in any of the code you've shown.

By not using casts needlessly, and using the C++ style casts (like
static_cast, reinterpret_cast, dynamic_cast, const_cast) where you
absolutely need one, you make it possible to /search/ for casts.

Searching for casts can be relevant because casts are a main source of
bugs -- which is the main reason to avoid them. ;-)


>>>> Having done all the above the program crashes on using an invalid
>>>> pointer txtrptr in [render.cpp] at line 62, which is due to using an
>>>> uninitialized member "d3dlr" (presumably there should have been an
>>>> earlier call to FractalImage::LockRectangle, but no such).
>>> That is uninitialized? It calls LockRectangle() right
>>> in there @ line 46.
>> I'm just reporting what it did. There was no actual call to that
>> function at run-time, before the crash. As to why that should happen,
>> well. :-)
>>
>
> Uh oh...
>
> Why wouldn't it call? That does not make any sense! It
> calls on my machine.

Checking...

This happens with menu choice "New fractal...".

Oops, I said something wrong (hasty me). LockRectangle /is/ called, but
the section of code there that initializes the "d3dlr", where I
naturally placed the breakpoint, is within

if(LockStatus == FALSE) { ... }

and LockStatus has a non-zero value, apparently uninitialized.

Summing up, I think it would really help if you tried very hard to do
/guaranteed/ initialization. Not calling Init-functions. Using
constructors that either initialize everything successfully, or throw.


[snip]


> The constructors do throw exceptions if they cannot initialize
> something
> completely and successfully. So it would be OK to remove all
> initialization
> checks except the exception throwing, then?

Yes, when the other aspects are fixed. By that I mean, not calling
Init-functions that call other functions... Using just constructors,
and even introducing dummy private base classes to do this.

Now as mentioned that isn't ideal. It's just a technical fix. Ideal
would be some redesign.

But by limiting yourself to a very harsh initialization regime, you'll
avoid pitfalls that otherwise could and probably would strand you (until
you gain more experience with initialization concerns in C++).

Cheers, & hth.,

- Alf


PS: *PLEASE DON'T QUOTE SIGNATURES!*

Erik Wikström

unread,
Sep 1, 2007, 7:20:06 PM9/1/07
to
On 2007-09-01 23:17, mike3 wrote:
> On Sep 1, 2:45 pm, "BobR" <removeBadB...@worldnet.att.net> wrote:
>> mike3 <mike4...@yahoo.com> wrote in message...
>> > On Sep 1, 12:57 am, "Alf P. Steinbach" <al...@start.no> wrote:

> <snip>
>> > I must be using a really crappy C++ compiler then as
>> > it allows that stuff.
>>
>> Then set it up for standard compliance, and raise the warning levels.
>>
>
> What compiler do you use, by the way? I've got a
> version of the GNU compilers on my system too,
> and I could feed the non-Windows stuff through
> it. If you're using GNU compilers (as I've
> assumed from your "GNU don't play that!" comment),
> could you explain how you do this (the "set it up
> for standard compilance" part. I already know
> how to raise the warning level.).

-std=c++98

--
Erik Wikström

mike3

unread,
Sep 1, 2007, 7:44:13 PM9/1/07
to
On Sep 1, 5:06 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * mike3:
>
>
>
> > What would be a better compiler, by the way? I've only
> > got this one since I didn't have to pay money for it
> > and I do not have a lot of money.
>
> It seems you forgot to state which compiler you're using.
>

I use the Borland C++ Builder 5.5 Command line tools.

> However, seeing as this is Windows programming, Visual C++ 8.0 is fairly
> good and gratis. Including an IDE, which, unfortunately, is crappy.
>

Gratis, really?

Is there a "stripped" version that has only the
C++ compilers, like with the Borland thing?

> [snip]
>
> > Then I'd be curious to know. Does this require a cast,
> > to get the value of the pointer for our error information?:
>
> > FG3DError SomeRoutine(BigFloat *a)
> > {
> > FG3DError err;
>
> > <blah blah blah>
>
> > if(<some operation on "a" failed>)
> > return(FG3DError(<Error code>, a)); <--- here
> > else
> > return(FG3DError(FG3D_SUCCESS));
> > }
>
> Do something like
>
> void someRoutine( BigFloat const& a )
> {
> // some operation on "a"
> }
>
> If "some operation" fails it will throw an exception.
>

What if the operation though is something that returns
an error value instead? Oh and when I throw the exception
I also need to convert a pointer to give additional
information to whatever handler catches the exception,
(there's handlers in any area where exceptions may
get thrown out of) for example to show that an
operation on "a" failed.

Should there be _no_ functions that return error
values, and instead _always_ throw exceptions when
they fail (as that way you don't have to worry about
neglecting an error check around one, you can just
keep a few exception handlers at various levels,
etc.?)?

> Notice how extremely much simpler this is, in addition to be much more safe.
>
> > And this?
>
> > long MultiplyShorts(short b, short c)
> > {
> > long a;
>
> > a = b*c;
>
> > return(a);
> > }
>
> Here you need conversion:
>
> inline long productOf( short a, short b )
> {
> long aLong const = a;
> return aLong*b;
> }
>
> or
>
> inline long productOf( short a, short b )
> {
> return (a+0L)*b;
> }
>
> Since this function is evidently intended to be used in expressions, the
> name has been changed to indicate the result rather than the operation
> (like, instead of "computeSin", just "sin").
>

I actually do not have a function like that in my
program, but the situation shown in that minimal
function is often found in more complex functions
like the bignum routines, for example. So then
I'd need to create ad hoc variables specifically
for the purpose of converting?

> > Will this give the full "long" result
>
> No, in the code you showed the arguments would be promoted to int, the
> computation done as int, and only then the result converted to long.
>

So then you have to typecast, right?

> > or
> > do I need to typecast b and c to "short"?
>
> ?
>

I meant, typecast to "long", sorry.

> [snip]
>
> > double DivideInts(int a, int b)
> > {
> > double t;
>
> > t = a/b;
>
> > return(t);
> > }
>
> > Does that give a full floating-point double-
> > precision quotient of a and b or an integer one?
>
> Integer.
>

So then would a typecast be a good idea?

Or is does this do it, and is it "proper"?:

---


double DivideInts(int a, int b)
{

double adbl = a;
double bdbl = b;

return(adbl/bdbl);
}
---

(No typecasting)

> > By the _C++ standard_, remember. See, in all
> > three of these situations I've used a cast, and
> > it is these situations that account for the vast
> > majority of my cast use.
>
> No need to use casts in any of the code you've shown.
>
> By not using casts needlessly, and using the C++ style casts (like
> static_cast, reinterpret_cast, dynamic_cast, const_cast) where you
> absolutely need one, you make it possible to /search/ for casts.
>
> Searching for casts can be relevant because casts are a main source of
> bugs -- which is the main reason to avoid them. ;-)
>

I've got nearly all the casts converted, so now I
can start removing them.

> >>>> Having done all the above the program crashes on using an invalid
> >>>> pointer txtrptr in [render.cpp] at line 62, which is due to using an
> >>>> uninitialized member "d3dlr" (presumably there should have been an
> >>>> earlier call to FractalImage::LockRectangle, but no such).
> >>> That is uninitialized? It calls LockRectangle() right
> >>> in there @ line 46.
> >> I'm just reporting what it did. There was no actual call to that
> >> function at run-time, before the crash. As to why that should happen,
> >> well. :-)
>
> > Uh oh...
>
> > Why wouldn't it call? That does not make any sense! It
> > calls on my machine.
>
> Checking...
>
> This happens with menu choice "New fractal...".
>
> Oops, I said something wrong (hasty me). LockRectangle /is/ called, but
> the section of code there that initializes the "d3dlr", where I
> naturally placed the breakpoint, is within
>
> if(LockStatus == FALSE) { ... }
>
> and LockStatus has a non-zero value, apparently uninitialized.
>
> Summing up, I think it would really help if you tried very hard to do
> /guaranteed/ initialization. Not calling Init-functions. Using
> constructors that either initialize everything successfully, or throw.
>

The structure, "FractalImage" has a real constructor,
but I only added the LockStatus flag in LATER, and FORGOT
to put it in the constructor! Dang!!!

It works now! The bug has been fixed!

The Init functions are *pnly* and I say again, *ONLY*
called in CONSTRUCTORS, period. And *always* called from
them. They're just there to save a bit of cutting-and-
pasting. At no point are they called anywhere else.

> [snip]
>
> > The constructors do throw exceptions if they cannot initialize
> > something
> > completely and successfully. So it would be OK to remove all
> > initialization
> > checks except the exception throwing, then?
>
> Yes, when the other aspects are fixed. By that I mean, not calling
> Init-functions that call other functions... Using just constructors,
> and even introducing dummy private base classes to do this.
>
> Now as mentioned that isn't ideal. It's just a technical fix. Ideal
> would be some redesign.
>

Could you tell me where my design is wanting, by the way?
I'd like to know so I can improve it.

> But by limiting yourself to a very harsh initialization regime, you'll
> avoid pitfalls that otherwise could and probably would strand you (until
> you gain more experience with initialization concerns in C++).
>

I try to make sure it's all initialized, but as I add
more to the classes sometimes I forget to add something
(like the dilemma that caused this whole problem) to the
initializing procedures. That's called "human error",
and it's bound to happen eventually.

> Cheers, & hth.,
>
> - Alf
>
> PS: *PLEASE DON'T QUOTE SIGNATURES!*
>

Signature snipped.

Duane Hebert

unread,
Sep 1, 2007, 8:25:03 PM9/1/07
to
> I use the Borland C++ Builder 5.5 Command line tools.
>
>> However, seeing as this is Windows programming, Visual C++ 8.0 is fairly
>> good and gratis. Including an IDE, which, unfortunately, is crappy.
>>
>
> Gratis, really?
>
> Is there a "stripped" version that has only the
> C++ compilers, like with the Borland thing?

I think it just does c++ but it has an IDE. You can also get Borland's
Turbo
Explorer that's based on BDS2006. It has an IDE and a newer compiler
than 5.5. Or just get both and see what you like. Both are free.


mike3

unread,
Sep 1, 2007, 8:31:16 PM9/1/07
to

Thanks.

> --
> Erik Wikström

mike3

unread,
Sep 1, 2007, 8:31:52 PM9/1/07
to

What's it called, anyway?

Alf P. Steinbach

unread,
Sep 1, 2007, 8:46:27 PM9/1/07
to
* mike3:

> On Sep 1, 5:06 pm, "Alf P. Steinbach" <al...@start.no> wrote:
>> * mike3:
>>
>>> What would be a better compiler, by the way? I've only
>>> got this one since I didn't have to pay money for it
>>> and I do not have a lot of money.
>> It seems you forgot to state which compiler you're using.
>>
>
> I use the Borland C++ Builder 5.5 Command line tools.
>
>> However, seeing as this is Windows programming, Visual C++ 8.0 is fairly
>> good and gratis. Including an IDE, which, unfortunately, is crappy.
>>
>
> Gratis, really?

Yep.


> Is there a "stripped" version that has only the
> C++ compilers, like with the Borland thing?

Not as far as I know, but unless it's very different from 7.1 you can
use the command line tools separately from the IDE.


>> [snip]
>>
>>> Then I'd be curious to know. Does this require a cast,
>>> to get the value of the pointer for our error information?:
>>> FG3DError SomeRoutine(BigFloat *a)
>>> {
>>> FG3DError err;
>>> <blah blah blah>
>>> if(<some operation on "a" failed>)
>>> return(FG3DError(<Error code>, a)); <--- here
>>> else
>>> return(FG3DError(FG3D_SUCCESS));
>>> }
>> Do something like
>>
>> void someRoutine( BigFloat const& a )
>> {
>> // some operation on "a"
>> }
>>
>> If "some operation" fails it will throw an exception.
>>
>
> What if the operation though is something that returns
> an error value instead?

The you convert to exception.

Fair warning: code below is my preferred way but many programmers find
it unnatural. If you find it unnatural, just replace "||" with "if".

bool throwX( char const s[] ) { throw std::runtime_error( s ); }

void someRoutine( BigFloat const& a )
{

someOp( a ) == NO_ERROR || throwX( "someRoutine: someOp failed" );
}


> Oh and when I throw the exception
> I also need to convert a pointer to give additional
> information to whatever handler catches the exception,
> (there's handlers in any area where exceptions may
> get thrown out of) for example to show that an
> operation on "a" failed.

That seems to a requirement that stems from a particular current
solution. When replacing the current solution the requirement then
disappears.

> Should there be _no_ functions that return error
> values, and instead _always_ throw exceptions when
> they fail (as that way you don't have to worry about
> neglecting an error check around one, you can just
> keep a few exception handlers at various levels,
> etc.?)?

Personal preference. There is a run-time cost associated with throwing
exceptions, and that needs to be weighted against clarity and ease of
programming: running time versus programmer's time and correctness. But
in general, as long as the program is fast enough, exceptions are in my
experience preferable even when the situation is not "exceptional".
However, it's /very important/ to think about simplicity of /usage/.
For if using the function will then require a try/catch in the immediate
caller for the most common usage, then exceptions are strongly
contra-indicated -- most try/catch-es indicate a possible improvement.


[snip]


>>> Will this give the full "long" result
>> No, in the code you showed the arguments would be promoted to int, the
>> computation done as int, and only then the result converted to long.
>>
>
> So then you have to typecast, right?

Nope.


[snip]
>>> double DivideInts(int a, int b)
>>> {
>>> double t;
>>> t = a/b;
>>> return(t);
>>> }
>>> Does that give a full floating-point double-
>>> precision quotient of a and b or an integer one?
>> Integer.
>>
>
> So then would a typecast be a good idea?
>
> Or is does this do it, and is it "proper"?:
>
> ---
> double DivideInts(int a, int b)
> {
> double adbl = a;
> double bdbl = b;
>
> return(adbl/bdbl);
> }
> ---
>
> (No typecasting)

This is good, but perhaps even better:

double doubleDiv( int a, int b ) { return 1.0*a/b; }

For some reason I like one-liners... :-)

Any half-decent compiler should optimize away the "1.0*". What it does
is to force a promotion to double of a and b. Before anything else.


[snip]


> It works now! The bug has been fixed!

Good.


> The Init functions are *pnly* and I say again, *ONLY*
> called in CONSTRUCTORS, period. And *always* called from
> them. They're just there to save a bit of cutting-and-
> pasting. At no point are they called anywhere else.

By expressing them as constructors (of e.g. a private base class) you
express that in code, /ensuring/ that they're not called from anywhere
else, and so making it completely safe to remove initialization checks.


[snip]


> Could you tell me where my design is wanting, by the way?
> I'd like to know so I can improve it.

Please note first that /every/ design is wanting.

There is no such thing as a prefetc design.

So the question is where to draw the line of possible improvement versus
work.

Since the present design is causing trouble, that line is not yet reached.

I'd start by a physical repackaging, not design. Currently, 'main.h'
(or something) is included everywhere, and a module's implementation
does not include the module's own header file. That should be exactly
opposite, for a great number of reasons, one of which is that currently
any change of 'main.h' forces a recompilation of (nearly) everything.

The main design problem I saw, with just a cursory look at the code, was
a mix of very high level (abstract operations) and low level (pointers,
casting), an abstraction gap, indicating one or more missing
intermediate levels.

Try to encapsulate low-level operations in some not-very-high-level
classes. For example, such encapsulation classes, or functions, do all
pointer stuff, translate from error codes to exceptions, etc. Just
getting that bug-inducing low level stuff /out of the way/, packaged.

Else-thread I have already mentioned another aspect of that high level
low level clash, that it would be a good idea to use std::vector instead
of raw arrays and pointers.

I think the above is the most important. But since no design is
prefetc, having done this other possibilities (including replacing
Init-functions with constructors, if not yet done) will suggest
themselves. The important thing then is to be very aware of whether the
improvements fix current bugs, prevent future ones, help future
maintainance, help reuse, or what. If the gain is not clear, but is
just "feels more elegant", then possibly the line has been reached.


[snip]
> Signature snipped.

Ah, thanks.

Cheers, & hth.,

- Alf

--

BobR

unread,
Sep 1, 2007, 8:49:09 PM9/1/07
to

mike3 <mike...@yahoo.com> wrote in message...

> On Sep 1, 2:45 pm, "BobR" <removeBadB...@worldnet.att.net> wrote:
> >

WHAT THE.... I don't see my post, but, it must be somewhere... you are
replying to it. ????

>
> <snip>
> > > Why couldn't it compile with those in?
> >
> > It's windows code. GNU don't play that!
> >
>
> He was using GNU compilers?

No. GNU is an operating system (OS), you might know it (incorrectly) as
Linux (which is a popular 'kernel'). The proper way to refer to it is
"GNU/Linux", (assuming the OS is GNU and the kernel is Linux).

> I thought there
> were versions of the GNU compilers for Windows.

That would be the GCC ports to windows, "MinGW" or "Cygwin".


> If his compiler, GNU or otherwise, was unable
> to support Windows he couldn't have run the
> program as the whole "main" thing, "wnd" stuff
> was all Windows. I'm guessing his compiler did
> support Windows since he was able to run it
> without modifications _that_ extensive.

What I was getting at is that with the windows stuff it couldn't compile/run
on an GNU/Linux system (unless it was cross-compiled, and run in an emulator
(like Wine)). The windows part is not considered on-topic in this NG.

>
> <snip>
> > > I must be using a really crappy C++ compiler then as
> > > it allows that stuff.
> >
> > Then set it up for standard compliance, and raise the warning levels.
> >
>
> What compiler do you use, by the way?

GCC (MinGW on the win partition)

> I've got a
> version of the GNU compilers on my system too,
> and I could feed the non-Windows stuff through
> it.

If it's MinGW or Cygwin, it most likely has the windows headers, and you
will be able to compile window$ programs.

> If you're using GNU compilers (as I've
> assumed from your "GNU don't play that!" comment),
> could you explain how you do this (the "set it up
> for standard compilance" part. I already know
> how to raise the warning level.).

For GCC, use compiler flags -ansi -pedantic, and/or one of the 'std=' flags.
(no compiler is 100% standard compliant, though I've heard Comeau comes
close.).

> >
> > > So then it casts it automatically, you don't need all
> > > that C-style stuff, then? Darn I'm too paranoid.
> >
> > If you must, use the C++ casts so you get the proper warnings/errors.
>
> Well I've been converting my main program to use
> these.

But only where the compiler complains and you are *sure* it is ok to
convert, right? <G>
The first thing to do with C-style casts is remove them. Then if the
compiler barks at you, feed it an proper C++ cast.
If you're not sure, start with a static_cast, it's the safest. Be careful
with the rest.

[ some is my opinion. Corrections welcome. ]
--
Bob R
POVrookie


mike3

unread,
Sep 1, 2007, 10:10:18 PM9/1/07
to
On Sep 1, 6:46 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * mike3:
>
>
>
>
>
> > On Sep 1, 5:06 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> >> * mike3:
>
> >>> What would be a better compiler, by the way? I've only
> >>> got this one since I didn't have to pay money for it
> >>> and I do not have a lot of money.
> >> It seems you forgot to state which compiler you're using.
>
> > I use the Borland C++ Builder 5.5 Command line tools.
>
> >> However, seeing as this is Windows programming, Visual C++ 8.0 is fairly
> >> good and gratis. Including an IDE, which, unfortunately, is crappy.
>
> > Gratis, really?
>
> Yep.
>

Cool. What is it called, anyway?

> > Is there a "stripped" version that has only the
> > C++ compilers, like with the Borland thing?
>
> Not as far as I know, but unless it's very different from 7.1 you can
> use the command line tools separately from the IDE.
>

Where can I get it, anyway?

>
>
>
>
> >> [snip]
>
> >>> Then I'd be curious to know. Does this require a cast,
> >>> to get the value of the pointer for our error information?:
> >>> FG3DError SomeRoutine(BigFloat *a)
> >>> {
> >>> FG3DError err;
> >>> <blah blah blah>
> >>> if(<some operation on "a" failed>)
> >>> return(FG3DError(<Error code>, a)); <--- here
> >>> else
> >>> return(FG3DError(FG3D_SUCCESS));
> >>> }
> >> Do something like
>
> >> void someRoutine( BigFloat const& a )
> >> {
> >> // some operation on "a"
> >> }
>
> >> If "some operation" fails it will throw an exception.
>
> > What if the operation though is something that returns
> > an error value instead?
>
> The you convert to exception.
>

I could, but I need to send the value of that
pointer in a generic 32-bit integer variable.

> Fair warning: code below is my preferred way but many programmers find
> it unnatural. If you find it unnatural, just replace "||" with "if".
>
> bool throwX( char const s[] ) { throw std::runtime_error( s ); }
>
> void someRoutine( BigFloat const& a )
> {
> someOp( a ) == NO_ERROR || throwX( "someRoutine: someOp failed" );
> }
>
> > Oh and when I throw the exception
> > I also need to convert a pointer to give additional
> > information to whatever handler catches the exception,
> > (there's handlers in any area where exceptions may
> > get thrown out of) for example to show that an
> > operation on "a" failed.
>
> That seems to a requirement that stems from a particular current
> solution. When replacing the current solution the requirement then
> disappears.
>

So then just don't tell what the "offending" operand
was, right? Or invent some ad hoc coding scheme?
I don't like those as I find them hard to maintain.

> > Should there be _no_ functions that return error
> > values, and instead _always_ throw exceptions when
> > they fail (as that way you don't have to worry about
> > neglecting an error check around one, you can just
> > keep a few exception handlers at various levels,
> > etc.?)?
>
> Personal preference. There is a run-time cost associated with throwing
> exceptions, and that needs to be weighted against clarity and ease of
> programming: running time versus programmer's time and correctness. But
> in general, as long as the program is fast enough, exceptions are in my
> experience preferable even when the situation is not "exceptional".
> However, it's /very important/ to think about simplicity of /usage/.
> For if using the function will then require a try/catch in the immediate
> caller for the most common usage, then exceptions are strongly
> contra-indicated -- most try/catch-es indicate a possible improvement.
>

OK. See, that's the thing I try to do. I throw exceptions
where they're needed, like if operator "+" fails, or the
constructor fails, or something, but for other things like
a casual call to reset coordinates for a zoom, I go
and return error codes, to avoid the expensive and
ugly-looking "try...catch" blocks everywhere.

PS. The program is _not_ fast enough right now, but I'm not
going to bother optimizing it now since I want to get it to
a well-working and _stable_ version first.

> [snip]
>
> >>> Will this give the full "long" result
> >> No, in the code you showed the arguments would be promoted to int, the
> >> computation done as int, and only then the result converted to long.
>
> > So then you have to typecast, right?
>
> Nope.
>

OK.

<snip>


> > (No typecasting)
>
> This is good, but perhaps even better:
>
> double doubleDiv( int a, int b ) { return 1.0*a/b; }
>
> For some reason I like one-liners... :-)
>
> Any half-decent compiler should optimize away the "1.0*". What it does
> is to force a promotion to double of a and b. Before anything else.
>

Alright.

> [snip]
>
> > It works now! The bug has been fixed!
>
> Good.
>

Yep.

> > The Init functions are *pnly* and I say again, *ONLY*
> > called in CONSTRUCTORS, period. And *always* called from
> > them. They're just there to save a bit of cutting-and-
> > pasting. At no point are they called anywhere else.
>
> By expressing them as constructors (of e.g. a private base class) you
> express that in code, /ensuring/ that they're not called from anywhere
> else, and so making it completely safe to remove initialization checks.
>

So then would making the code explicit, even though
it's repetitive and looks ugly, in the BigFloat()
constructors be a good idea?

> [snip]
>
> > Could you tell me where my design is wanting, by the way?
> > I'd like to know so I can improve it.
>
> Please note first that /every/ design is wanting.
>
> There is no such thing as a prefetc design.
>

I know, I didn't say there was.

> So the question is where to draw the line of possible improvement versus
> work.
>

That's right.

> Since the present design is causing trouble, that line is not yet reached.
>
> I'd start by a physical repackaging, not design. Currently, 'main.h'
> (or something) is included everywhere, and a module's implementation
> does not include the module's own header file. That should be exactly
> opposite, for a great number of reasons, one of which is that currently
> any change of 'main.h' forces a recompilation of (nearly) everything.
>

So then is it OK to include all the external library headers
again and again without an easy reference file like main.h?

> The main design problem I saw, with just a cursory look at the code, was
> a mix of very high level (abstract operations) and low level (pointers,
> casting), an abstraction gap, indicating one or more missing
> intermediate levels.
>
> Try to encapsulate low-level operations in some not-very-high-level
> classes. For example, such encapsulation classes, or functions, do all
> pointer stuff, translate from error codes to exceptions, etc. Just
> getting that bug-inducing low level stuff /out of the way/, packaged.
>

What exactly would it be a good idea to encapsulate, anyway?
Like how would one encapuslate all the pointer stuff, anyway?
There's one place where I need to manipulate the pointers
low-level directly for speed, and that's in that tiny amount
of core routines used for computing the fractals with bignum
arithmetic (the "FastXXXX" bignum routines that are called
in the tight inner loops of the fractal formulas. In that
case, a call to a "pointer class"'s member functions would
eat time like crazy since those arithmetic routines are being
called millions of times. Extra function calls for every
pointer manipulation would just add too much cost there.).
But outside of that, what would I do?

Is this an example of the type of mixed abstraction you
were talking about?:

---
void SomeFunction(int something)
{
FG3DError err;

<blah blah blah>

if(<something goes wrong>) throw Exception(err.dwErrCode,
err.dwAdditionalInformation);

<blah blah blah>
}
---

which accesses the members of "err" directly,
versus

---
void SomeFunction(int something)
{
FG3DError err;

<blah blah blah>

if(<something goes wrong>) throw Exception(err);

<blah blah blah>
}
---

which doesn't?


> Else-thread I have already mentioned another aspect of that high level
> low level clash, that it would be a good idea to use std::vector instead
> of raw arrays and pointers.
>

I'll give that a try and see what happens.

> I think the above is the most important. But since no design is
> prefetc, having done this other possibilities (including replacing
> Init-functions with constructors, if not yet done) will suggest
> themselves. The important thing then is to be very aware of whether the
> improvements fix current bugs, prevent future ones, help future
> maintainance, help reuse, or what. If the gain is not clear, but is
> just "feels more elegant", then possibly the line has been reached.
>
> [snip]
>
> > Signature snipped.
>
> Ah, thanks.
>

You're welcome.

LR

unread,
Sep 1, 2007, 10:33:59 PM9/1/07
to
Alf P. Steinbach wrote:

> Try to encapsulate low-level operations in some not-very-high-level
> classes. For example, such encapsulation classes, or functions, do all
> pointer stuff, translate from error codes to exceptions, etc. Just
> getting that bug-inducing low level stuff /out of the way/, packaged.
>
> Else-thread I have already mentioned another aspect of that high level
> low level clash, that it would be a good idea to use std::vector instead
> of raw arrays and pointers.

And don't over look the ease of use issues, for example, want to set all
the elements of a std::vector<int> to zero?

std::vector<int> t;
// ...more code here...
t.assign(t.size(),0);

I'd like to add that getting rid of all, or at least as much as you can,
the manipulation of char arrays and pointers by using std::string
instead might go some way to reducing work. String streams can be
pretty useful along those lines too.

Sure, the buffers you create are probably, most likely, expected to be,
big enough. But then you'll discover to your sorrow that they weren't.
Annoying that.

Also, I find that some simple things make code easier to deal with.

For example, if I have a function
void f(const int a);
that gets called a few dozen times with double, like so:
f((int)1.3); // or something
it's easier to just add another function (or ctor, or method, with
appropriate syntax accordingly) like
void f(const double a);
rather than doing all those casts, even if the second calls the first.
That'll still look a little cleaner.

And I'd like to repeat what has been already mentioned. Be careful with
those casts. Particularly with casting pointers to an integral type or
vice-versa, in general this is not wise.

LR

mike3

unread,
Sep 3, 2007, 8:05:49 PM9/3/07
to

Any answers or comments yet?

mike3

unread,
Sep 5, 2007, 3:42:33 PM9/5/07
to
I still haven't heard any response yet.

But I would still really want to know what exactly to do
with improving the design. You suggested that I try
to add in "intermediate" levels of abstraction, with
low level classes to handle pointers, etc. Wouldn't I
then need to set up a class for each and every data type
I want to make an array? Or would using std::vector, etc.
be acceptable?

Would it be a good idea to, for example, with the BigFloat
thing, encapsulate the digits and all that into a separate
"RawInt" class that is essentially an integer type, from
which BigFloat would be made a derived class? This would
help get rid of the nasty Init functions that I heard were
such a bad idea (since even if their use is limited to
constructors, it is still possible one may accidentally
slip and call them from somewhere else), since then each
constructor for the different varieties of BigFloat would
not need those to initialize the digit array as that's
taken care of by RawInt's constructor. And the RawInt
routines would be able to do arithmetic of parts of the
RawInts to other parts, so that all the "pointer gymnastics"
seen in the floating point routines would be handled by
the lower-level RawInt, and then finally through the
safer and better std::vector arrays.

That would reorganize it to something like

class RawInt
{
protected:
std::vector<DIGIT> digits; <--- note the use of std::vector!
int length;
public:
RawInt();
~RawInt();
<everything in rawint.cpp remade into member
functions, reworked to handle disparate lengths,
etc.>
}

and

class BigFloat : private RawInt
{
private:
u32 signexp; /* sign-exponent combination */
public:
<everything in bigfloat.cpp, etc.>
}

.

(and reworking all the arithmetic stuff appropriately,
of course.)

Does that sound like a good idea? I've already started
doing it since it looks good to me.

PS. I've also changed all instances of "DIGIT32" to
"DIGIT" in the full program in case I want to make
a 64-bit version for 64-bit processors when I get one,
and reworked it a bit so that 32-bit-specific things
have been turned into a few macros and defines that
can be easily changed to resize the digit being
used.

Gianni Mariani

unread,
Sep 6, 2007, 8:02:55 PM9/6/07
to
mike3 wrote:
> I still haven't heard any response yet.

I'm not sure what the requirements you're trying to achieve.

mike3

unread,
Sep 6, 2007, 10:14:53 PM9/6/07
to

If you read some of the earlier messages here you can see
what I was going after. I got a suggestion that the design
I had was more prone to having bugs, since it had an
"abstraction gap" with "mixing" low and high level stuff.

mike3

unread,
Sep 8, 2007, 4:40:48 PM9/8/07
to

Any comment?

mike3

unread,
Sep 10, 2007, 7:33:31 PM9/10/07
to

Hello?

Gianni Mariani

unread,
Sep 10, 2007, 9:19:57 PM9/10/07
to

I didn't go through all the postings to divine your requirements. I
probably won't have the time or desire to do that for you. If you'd
like me to look at it (or anyone else for that matter), I'd suggest
making it as easy as possible for them to understand what you're trying
to do.

mike3

unread,
Sep 10, 2007, 9:40:23 PM9/10/07
to
On Sep 10, 7:19 pm, Gianni Mariani <gi3nos...@mariani.ws> wrote:
> mike3 wrote:
> > On Sep 8, 2:40 pm, mike3 <mike4...@yahoo.com> wrote:
> >> On Sep 6, 8:14 pm, mike3 <mike4...@yahoo.com> wrote:
>
> >>> On Sep 6, 6:02 pm, Gianni Mariani <gi3nos...@mariani.ws> wrote:
> >>>> mike3 wrote:
> >>>>> I still haven't heard any response yet.
> >>>> I'm not sure what the requirements you're trying to achieve.
> >>> If you read some of the earlier messages here you can see
> >>> what I was going after. I got a suggestion that the design
> >>> I had was more prone to having bugs, since it had an
> >>> "abstraction gap" with "mixing" low and high level stuff.
> >> Any comment?
>
> > Hello?
>
> I didn't go through all the postings to divine your requirements. I
> probably won't have the time or desire to do that for you. If you'd
> like me to look at it (or anyone else for that matter), I'd suggest
> making it as easy as possible for them to understand what you're trying
> to do.

I explained briefly what it is, in my own posting above.
One of the people here said the program had an
"abstraction gap", in which it was said there was a
wide difference between high levels of abstraction like
bignums, and low levels like pointers and casting, and
it was suggested that I encapsulate pointers, and
coverting errors to exceptions, and other low level
stuff (which was not specified), into a set of low
level classes and functions. So what I was trying to do
here was smooth that gap out a bit. The reason for
this being objectionable is not that it *contains*
bugs, but that it is *prone* to bugs, which makes
the software harder to maintain.

If want to to read that post, and that one alone, without
hunting through the thread, here is a straight link to it:

http://groups.google.com/group/comp.lang.c++/msg/a66278b77597d648

Here's a quote:

"Try to encapsulate low-level operations in some not-very-high-level
classes. For example, such encapsulation classes, or functions, do
all
pointer stuff, translate from error codes to exceptions, etc. Just
getting that bug-inducing low level stuff /out of the way/, packaged.


Else-thread I have already mentioned another aspect of that high
level
low level clash, that it would be a good idea to use std::vector
instead
of raw arrays and pointers. "

So therefore what I was trying to do with my program was
to replace the slew of "raw integer" routines with a RawInt
class, and use std::vector<> for arrays/pointers. This
std::vector<> would then initialize/free the memory for
the digits, eliminating the need for "Init" functions that
were said to be bad since there's no way to guarantee you
might not use them out of negligence is places where
they should not be used, even if intended to be called only
from constructors. In addition, I think it would smooth
that gap I mentioned to some degree. As then instead of
having this:

direct arrays < BigFloat

we have

direct arrays < std::vector < RawInt < BigFloat.

Does this help?

LR

unread,
Sep 10, 2007, 11:30:01 PM9/10/07
to
mike3 wrote:

[snip long explanation]
> Does this help?

I'm having some trouble understanding what you want.

Do you have a question that you want answered?

LR

mike3

unread,
Sep 14, 2007, 9:43:42 PM9/14/07
to

Did you get my post?

mike3

unread,
Sep 16, 2007, 4:05:53 PM9/16/07