|
By Reg Charney
Contrary to the title, I hope to make this a little treatment a
little fun. The first example comes from a manual on Q&A
Software. See if you can identify the error:
void testFcn()
{
char *aPtr;
for (int i=0;i<500;i++)
aPtr = new char[100];
delete [] aPtr;
return;
} |
The manual explains:
“In this instance, only the memory allocated the last time
through the loop is freed. The other 499 times, memory was
allocated, the resulting pointer assigned to the same pointer. (aPtr),
but not released. If you follow the program in debugging mode, you’ll
see that after each call to new,
aPtr has a different
value. Using the same pointer variable each time you allocate memory
does not automatically free the memory that was associated with it
before. You must free the memory explicitly.”
It is true that there is a memory leak, but the simple solution
is to enclose the two statements following the for
in a pair of braces.
The next error is more subtle than the last one. Herb Sutter and
Jim Hyslop (www.gotw.ca) wrote a
light-hearted article on thread safety. A fragment like my
simplified example appeared:
class Car {
explicit Car();
private:
ostream& Ins(ostream&);
friend ostream& operator<<(ostream&,
Car&);
Mutex m_;
string rep_;
// ...
};
ostream& operator<<(ostream&
o, Car& c)
{
return c.Ins(o);
}
ostream& Car::Ins(ostream&
traffic)
{
Lock lock(m_);
traffic << rep_;
return traffic;
} // lock is released
|
Here the problem concerns the use of the Mutex
m_ inside the Car class.
Herb explains the three errors this way (excusing the
Shakespearean English):
“Thou shalt not make objects thread-safe — it is a
perversion. Thread safety is good, but now every Car in the system
will incur the evil lock overhead whether that Car object is
actually ever used by more than one thread or not. This was one of
the mistakes in the early so-called ‘thread-safe’ Java
containers. Those designers soon learned the errors of their ways.
If an object can be used by multiple threads, it is the
responsibility of the outside code that owns that object, and that
code alone, to serialize all access to it. This too is encapsulation
and a striving after correctness.”
- “... it is a fundamental law that long-term locks are
anathema!”
- “... our standards require that all platform-specific calls
must be isolated only in the System module, for portability!”
For a fuller treatment of this whole subject, see his online
article at http://www.gotw.ca/publications/optimizations.htm.
On the ACCU-GENERAL mailing list, the following question
appeared:
“Why does the [following Java] switch give the error message
"<identifier> expected?"?”
switch (arrInts.[at])
{
//...
} |
James Dennet <jdennett@acm.org>
gave the following answers:
- What is “arrInts”?
- If it's an array, drop the “.”
If it's not an array, in Java you must
use arrInts.at(index) or
similar; Java lacks operator overloading, except for + on Strings,
so you can't have classes looking like built-ins.
However, I believe that this is another case of poor error
diagnostics. My first reaction was “What identifier?”, That is,
where is the identifier expected: before or after the switch
keyword, in the expression, or after the switch expression. A much
better error message would have been: “Scalar expression expected
in switch clause.” To quote The Java Programming Language,
3rd Edition by Ken Arnold, James Gosling, David Holmes published by
Addison-Wesley Pub Co; ISBN: 0-201-70433-1:
The switch expression must be of type char,
byte, short,
or int. All case
labels must be constant expressions - the expressions must contain
only literals or named constants initialized with constant
expressions - and must be assignable to the type of the switch
expression.
Most of you are not members of the ACCU, so you do not have
access the ACCU-GENERAL mailing list. I thought you might like to
listen in on a short exchange recently.
Why is it good to do this: std::string or
std::vector
I’ve noticed in many articles, authors insisting on writing
fully qualified names for members of the standard library, instead
of applying 'using directives' or 'using declarations'. Can somebody
please explain why this is encouraged? Should it be encouraged?
—Michael
I'd encourage it for two reasons:
- it can make the code clearer, and
- it works reliably.
There can be times, in writing template code, where the
uncertainty over which name will be chosen when using a using
declaration can be handy. Most often, though, you know that you want
the std version, so why not say it in the code?
There are those (not including myself) who think that the std::
is visual clutter, and hinders clarity. I guess that's subjective.
—James
You're not alone, I always explicitly qualify my names. I believe
it makes the code more readable since it leaves no question where
the name comes from. If for instance someone else were to read your
code and they came across a name they weren't familiar with they
wouldn't have to search for the declaration/definition. They could
instead pick up their copy of “The C++ Standard Library” or
documentation of any third party library as it would be far more
obvious where the name originates. A using directive does not help
identify such names and although a using declaration might be of
slightly more benefit it still has to be searched for.
Another reason I avoid using directives is that they are
transitive. A using directive that nominates one namespace may in
fact nominate several which is not immediately clear without
searching the namespace itself. I.e.,
namespace A
{
//...
}
namespace B
{
using namespace A;
//...
}
void f(void)
{
using namespace B;
// includes both A and B
//...
} |
If anything this reduces readability. Another example of
confusion:
template <typename
T>
class vector
{
T* ptr;
};
int main(void)
{
using namespace std;
vector<int> vi;
int s = vi.size();
return 0;
}
error: 'size' : is not a member
of 'vector<int>' |
Wouldn't that leave someone scratching their head for a while?
But wait a second ....
int main(void)
{
using std::vector;
vector<int> vi;
int s = vi.size();
return 0;
} |
All is well now! Lookup rules differ depending on whether you use
a using directive
or using declaration.
int main(void)
{
std::vector<int> vi;
int s = vi.size();
return 0;
} |
Ah, much better! :-)
—Rob
A question regarding traits
When creating a traits class one can use of the following two
conventions
struct SomeTraits
{
static const int error_code= -1;
}; |
or
struct SomeTraits
{
static int error_code() { return -1; }
}; |
Now obviously the above example is over-simplified, but the
question here is: What are the list members' preferences to using
functions in traits to return constant values vs. using ‘static
const’?
(Possibly a real world example to refer to is the eof()
in std::char_traits).
—Schalk
There's an obvious difference between the two, in that the first
example may be used in compile-time computations, while the latter
can't be used there. For example:
--- Start ---
struct TraitF // use
fcn
{
static const int val() { return 1; };
};
struct TraitV // use value
{
static const int val = 1;
};
template<int n>
class Test { };
int main()
{
Test<TraitF::val()> t; // Error in this line
// call is not allowed
// in const expr
Test<TraitV::val> t; // Ok
}; |
--- End ---
Note, some compilers (such as VC++) don't handle in-class
initialization of static constants, so you may have to use the “enum-hack”,
instead:
Also, such constants only work for integral types, not floating
point values or pointers.
—Terje
My application doesn't get to main()
I have an application that uses at least two dynamic libraries,
and it works fine in one environment but not another. I'm unsure
what to check now; I don't really understand how dynamic libraries
work, and so I don't know where to begin finding out what is wrong.
--Michael
Not enough information!
What environments? What specifically is the problem? How do you
use dynamic libraries? How are you linking?
You say it “doesn't even get to main” - are you sure you have
linked main in? Why do you think this is related to dynamic
libraries?
—Dave
If it's in Windows, you can use the DevStudio’s Depends
utility to see if it's not happy with either of your DLLs.
This might be because it can’t find them (path problem), or they
have a dependency which is not resolved (e.g. they use an OS
function which is not in your different environment) and therefore
can't be loaded.
—-Simon
Well, as a first step, tell us what the platforms / environments
you are working with are. If it's a UNIX platform, you'll want to
check out the LD_LIBRARY_PATH
variables; also, the ldd
tool will be invaluable.
There are similar things on Windows, but it's been a while since
I've done any serious work on that platform. So, the more details
you can give us on the context and the problem, the easier it'll be
for us to help you out.
—Burkhard
I'm going to guess that you'd on Windows, as some else pointed
out you have ldd and
a host of LD_LIBRARY_
environment variables if your on Uni*.
Typically I find this when you have an app which loads a DLL,
which in turn loads another DLL. When the first DLL fails to find
the second DLL you get "Cannot load library" (or something
similar) in a model dialog box and you pull your hair out because
you can see the DLL (the first one) is there.
Things to try:
- are you getting any link warnings? Could be you're trying to
load incompatible libraries, e.g. libcd.lib
and libcdmt.lib.
Clean them up.
- have a look at ImageFileExecution
option, its a registry setting that allows you to have a
debugger invoked when an application loads
- there is a similar one DllImageFile
(???) for DLLs, allows the debugger to be invoked when a
DLL loads
then there is a Windows tool called “depends”,
in the resource kit I think — actually there are two versions of
depends, a command line one and a GUI one, you want the GUI one. It
will allow you to look at a DLL and see what it is loading.
Try setting a break point on mainCRTstartup
and see what happens
- when you get that annoying little dialog box you may be able
to "attach to process" with your DLL and see where it
is
- check and double check your paths. Maybe do this at the
command line the dialog boxes are far too fiddly
And if none of that works come back and give us some more info.
—Allan
By Reg. Charney
I am writing this column from Israel. I came because I felt that
I needed to do something here to lessen the violence. I came here
with several ideas to get both sides talking. One main idea was that
there needs to be common ground. Since I despaired of governmental
agencies communicating — they had too many vested interests, I
needed to reach beyond them to the people themselves. This has
proven to be very difficult. The distortion field here is immense.
Both sides are affected and each side sees things almost totally in
its own terms. The Israelis see only innocent victims and madmen.
The Palestinians see suicide bombers as heroes and any strike
against the domineering Israelis, whether men, women or children, as
legitimate targets. I believed that there is one major problem: the
average person has no control over the honesty of the information
they get that to solve the problem, we need establish one-on-one
relationships between members of the opposite side.
However, the facts are more frightening than I imagined. There is
a well-respected organization, the Palestinian Center for Policy and
Survey Research (www.pcpsr.org), here that has done a very credible
job of conducting public opinion surveys of both the Israeli and the
Palestinian populations. Since I am here trying to reduce the
conflict long term, I was interested in the following questions and
the responses from the last survey done December 2001. Amongst the
Palestinians, the level of support for attacking Israeli solders and
settlers is 92%,, for attacking civilians inside Israel is 58%. A
Palestinian majority of 61% support armed conflict. On
reconciliation, only 6% of Palestinians support changing the school
curriculum to recognize Israel’s right to exist. Amongst
Palestinian, 91-98% view all Israeli violent acts as terror acts.
while 81-87% do not view violent acts against Israelis as acts of
terror.
How do we reconcile these differences?
Programming with Qt, 2nd
Edition.
By Matthias
Kalle Dalheimer, O'Reilly Verlag, GmbH und Co. KG 2002, ISBN
0-596-00064-2
This book is an absolute ‘must read’ for every Qt programmer
and strongly recommended for anyone facing the task of building
advanced GUI based applications. The book requires an intermediate
level of experience with C++ and understanding of object oriented
development principles.
Qt is a C++ class library providing a platform independent GUI
toolkit. Kalle describes and explains the important components of
the Qt toolkit while keeping an eye on the big picture of good
software practices.
Using this extraordinary toolkit, the author needs just two
chapters after the introduction to show how to design and implement
a nontrivial application with some advanced user interaction. A
chapter about Qt's sophisticated and elegant layout managers
concludes the first part of the book.
Kalle then shares his valuable insights about GUI design. This
may not belong here, but I am grateful for this advice.
The second part of the book covers the many possibilities that
the Qt toolkit provides including container classes over graphics
with and without OpenGL; multithreading; and Qt network programming.
A chapter about interfacing Qt with Perl, a chapter about using
and integrating Qt with the Visual Studio IDE as well as a thorough
introduction to the graphical interface builder 'Qt Designer'
conclude the book.
The book’s last two chapter, belong in the front and the
initial examples should make use of Qt Designer and Visual Studio
rather than bore the reader with the idiosyncrasies of the Unix
command line or scare him with ‘make’.
— Dr. Roland Krause
By Reg Charney
A number of things conspired to make this month’s Trend column
disappear. I am currently out of the country and the raw data gave
no clear indication of where the trend lines were going. This made
drawing meaningful conclusions difficult. From other sources, we
know that the Valley has been hit particularly hard since the
Internet Bubble burst. Trends will be back next month.
|