📄 borland.txt
字号:
It is notable that a number of posters on comp.lang.c++ have been confused by
including <stream.h> thinking they were getting <iostream.h>...
-----------------------------------------------------------------------------
<generic.h>: Instead of using the usual "name2" style macros, Borland
invented their own set of macros for concatenating pieces of names. Any code
using the Stroustrup-style macros (eg. code compatable with g++, CC, or
Zortech C++) will break. A work-around is to stick the following on the
bottom of your <generic.h>:
#define name2 _Paste2
#define name3 _Paste3
#define name4 _Paste4
This bug and its work-around is thanks to:
Pete Humphrey / pete@edsr.eds.com / 505-345-1863
EDS Research / 5951 Jefferson Street NE / Albuquerque, NM 87109-3432
-----------------------------------------------------------------------------
TC++ signals a compiler error when the LAST default parameter for a
constructor is initialized by a constructor for some other class. A
workaround is to add an extra dummy default parameter of some
predefined type like int. Ex: if A and B are classes, then:
This will be an error: A::A(B b = B(...));
But this is ok: A::A(B b = B(...), int dummy=0);
Thanks to:Zerksis Umrigar/umrigar@bingvaxu.cc.binghamton.edu/SUNY Binghamton NY
-----------------------------------------------------------------------------
When an object is created as a side effect of an expression, and the expression
is short-circuited, the destructor for the object seems to get called anyway:
class X {
public:
X create_copy_of_X() { return *this; } //Return *BY VALUE*
int whatever();
//...
};
main()
{
X x;
//...
if (0 && x.create_copy_of_X().whatever()) stmt;
//...
}
At the close of main(), TC++ calls a destructor on the copy of `x' even though
the copy was never properly constructed. This only happens when inline functns
are NOT inlined. Thanks to: Jamshid Afshar/jamshid@ccwf.cc.utexas.edu
-----------------------------------------------------------------------------
An explicit constructor in a by-value return statement, for example
String foo() { char* p; /*...*/ return String(p); }
is interpreted by TC++ to mean ``construct the return value right on the
stack'' (ie: not a temporary object, but the actual return location). TC++
does the right thing by not creating a temporary, otherwise it would have to
copy to the return location and then `destruct' the temporary. HOWEVER, TC++
then goes ahead an treats the constructed object as if it *were* a temporary,
and it tries to copy it to the return location, which is where it already is!
Thus the copy ctor is called with `this' pointing to *itself*. This is
disasterous if copy ctor allocates memory; Ex:
String::String(const String& S)
{
s=new char[S.len+1]; // If &S == this, changes S.s also!!!
strcpy(s, S.s); // Copy GARBAGE into itself
len = S.len;
}
WORKAROUNDS: [1] If there's a one-parameter ctor that will automatically
convert to the return value (such as String(char*) above), then you don't need
an explicit constructor in the return stmt (ex: ``return p'' would work just as
well). [2] If you need a more-than-one parameter ctor (ex: ``return
complex(re,im)'', then you can construct a temporary and return the temporary
by value. For example:
complex foo()
{ //...
complex my_return_value = complex(re, im);
return my_return_value;
}
Unfortunately this won't be as fast since it requires an extra copy ctor
and the temporary (``my_return_value'') has to be `destructed'.
-----------------------------------------------------------------------------
Missed Feature: There is a subtle C++ bug in the code below. Even though the
initialization list in String::String(const char*) looks like Len will get
initialized before s, in fact the initialization order is fixed by the position
within the class, which is just the opposite. Thus an arbitrary and
unpredictable amount of storage will be allocated! (I put this `missed
feature' in the `bug' report because TC++ users are used to TC++'s *excellent*
warnings, and they may be puzzled if the compiler silently accepts code which
is patently wrong. For example, TC++ complains about locals that are used
before they're initialized, and this is an analogous situation.)
class String {
char* s;
unsigned Len;
public:
String(const char* p); // char* --> String
//...
};
String::String(const char* p) : Len(strlen(p)), s(new char[Len+1])
{ /////// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
strcpy(s, p); /////// Missed feature: TC++ should warn here
} /////// Ex: `Len used before it is initialized'
-----------------------------------------------------------------------------
The following was contributed by Joseph Puglielli, Santa Barbara, CA
It has NOT been double checked by the editor of this list.
The #if/#else/#endif bracketed pair that follows should be functionally
equivalent, but they're not:
#include <iostream.h>
#include <fstream.h>
void error(const char*);
#if 1
class Reader {
ifstream input;
char data[100];
public:
Reader(const char* fname)
{ if (!input.open(fname, ios::nocreate | ios::binary))
error("can't open file in Reader::Reader(const char*)");
}
~Reader(const char* fname) { input.close(); }
void getin()
{ memset(data, '\0', 100);
if (!input) error("Reader::getin() -- input file is trashed");
for (int i = 0; i < 100 && !input.eof(); ++i)
{ char c; input.get(c); data[i] = c; }
}
};
main() { Reader r("input.txt"); r.getin(); }
#else
main()
{
ifstream input;
char data[100];
char* fname = "input.txt";
if (!input.open(fname, ios::nocreate|ios::binary)) error("can't open file");
memset(data, '\0', 100);
if (!input) error("main() -- input file is trashed");
for (int i = 0; i < 100 && !input.eof(); ++i)
{ char c; input.get(c); data[i] = c; }
input.close();
}
#endif
-----------------------------------------------------------------------------
The following was contributed by Joseph Puglielli, Santa Barbara, CA
It has NOT been double checked by the editor of this list.
The following two `x's shouldn't conflict, since `x' is a local `type'
in each class. However they do conflict.
class A { enum x { zero, one, two }; };
class B { enum x { apple, orange, pear }; };
-----------------------------------------------------------------------------
This is thanks to: Scott Schram / 72561,207 on compuserve / sshram on BIX:
When you compile with -N (stack checking ON), TC++ declares _stklen at the
first function definition (when it emits code to do the stack-overflow check).
The only way you can use it to extend the stack is to include <dos.h> *BEFORE*
your first function definition. Ex: this will fail:
int a(void) { return 0; } // Implicitly causes _stklen to be declared
unsigned _stklen = 20000; // This *RE*-declares _stklen...
main() { a(); return 0; }
Instead use this:
#include <dos.h> // EXPLICITLY declares _stklen
int a(void) { return 0; } // Implicitly causes _stklen to be declared
unsigned _stklen = 20000;
main() { a(); return 0; }
-----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -