Strings with Templates not working?

A

Andre Kostur

You were right. It works with cstddef.
But I don't understand yet why NULL is frowned upon in C++.
I already found similar information about what you said, but I didn't
find a logical explanation about the disadvantages with using NULL
instead of 0.

You don't want the (void*) in there since it won't be implicitly
convertable to all pointer types. You'd be forcing casts on yourself. As
to why people really don't like NULL, I'm not sure. I think it's a
historical thing (when most compilers were defining it with the void*
cast). I personally like to distinguish when I'm dealing with a "pointer
to nowhere" (NULL) vs. a number 0.
By the way. Is there some standard library collection about c++ like
the Java Doc in Java? I found a good collection on
http://www.cplusplus.com/. I guess that these libraries there are the
standard libraries.

Dinkumware has some online references (http://www.dinkumware.com/manuals/),
but I'd go out and get a copy of "The C++ Standard Library: A Tutorial and
Reference" by N. Josuttis (ISBN: 0-201-37926-0). That seems to be the most
commonly referenced book on this topic.
 
M

Markus Schoder

On Wed, 20 Jun 2007 21:41:13 +0200, Markus Pitha wrote:
[snip]
template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = new TKnoten();
T daten = 0;
!---->>^^^^^^^^^^^

T daten = "";
Or better yet, so it works with any type.

T daten;

Even better

T daten = T();

or it will not get initialised for POD and scalar types.
 
A

Andre Kostur

Yes, u were right. I only need to instance a new object while creating
a
new node in my list.
But I still don't understand why this works:

template <class T>
ListT<T>::~ListT() {
while (kopf->next != NULL) {
delete kopf;
kopf = kopf->next;

Undefined Behaviour. After you have deleted kopf, you may not
dereference it for any purpose.
}
delete kopf;
}

How about:

template <class T>
ListT<T>::~ListT() {
while (kopf->next != NULL) {
TKnoten * toDelete = kopf;
kopf = kopf->next;
delete toDelete;
}
delete kopf;
}
 
B

BobR

The 0 (zero) is one keypress, the NULL is five (if you count the shift-key).
[see the def below] It 'returns' a zero, so, why not just hit the '0' key?

int *pint( 0 );
vs.
int *pint( NULL );

I'll take the first. Simple, and you don't have to chase down a macro or
documentation to know what it is.

You don't want the (void*) in there since it won't be implicitly
convertable to all pointer types. You'd be forcing casts on yourself. As
to why people really don't like NULL, I'm not sure. I think it's a
historical thing (when most compilers were defining it with the void*
cast). I personally like to distinguish when I'm dealing with a "pointer
to nowhere" (NULL) vs. a number 0.

I could only find the def in "windef.h" (GCC(MinGW)3.3.1):

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void*)0)
#endif
#endif
 
J

James Kanze

For the record, doing either of these if you include any
standard header results in undefined behavior. Don't ever
define NULL yourself.
You were right. It works with cstddef.

Formally, NULL is defined any time you include any one of
clocale, cstddef, cstdio, cstdlib, cstring, ctime or cwchar, or
the corresponding .h headers. Any of the standard C++ headers
is allowed to include any of these headers, however, and so
might define NULL (or might not). If the goal is just to have
access to NULL, I would use stddef.h, because that is the
"canonical" one. (In the C standard, NULL is described in the
section describing stddef.h; in the sections for the other
headers, it simply states that NULL is defined as described in
the section for stddef.h.)
But I don't understand yet why NULL is frowned upon in C++.

It's not. A lot of C++ programmers use it.
I already found similar information about what you said, but I
didn't find a logical explanation about the disadvantages with
using NULL instead of 0.

The disadvantage that is usually given is that it gives a false
sense of type safety. Given something like:

template< typename T >
void f( T ) ;

"f( NULL )" will instantiate and call f<int> (or some other
integral type), and not some pointer type.

Of course, any decent compiler will generate a warning in this
case, which sort of deflates that argument.

At any rate, the prochain version of C++ will have a special
type and value for this, which works correctly.
By the way. Is there some standard library collection about
c++ like the Java Doc in Java?

The best one I know of is at the Dinkumware site.
 
J

James Kanze

Andre Kostur <[email protected]> wrote in message...
The 0 (zero) is one keypress, the NULL is five (if you count the shift-key).
[see the def below] It 'returns' a zero, so, why not just hit the '0' key?
int *pint( 0 );
vs.
int *pint( NULL );

That is the most stupid reason I've ever heard. You write code
to be read.
I'll take the first. Simple, and you don't have to chase down a macro or
documentation to know what it is.

NULL is part of the standard. You don't have to track down any
documentation to know what it is, any more than you do for
"int".

There are valid arguments against NULL (most of which are
negated by the fact that good compilers warn if you misuse it),
but this isn't one.
I could only find the def in "windef.h" (GCC(MinGW)3.3.1):

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void*)0)
#endif
#endif

There's a lot of historical issues floating around. Originally,
C didn't have void*, and 0 was the standard "null pointer
constant". This didn't change when void* was added to the
language, but in the MS-DOS world, the size of a pointer
depended on the compilation model (small, large, etc.), but the
size of an int didn't. This meant that if you passed NULL to a
vararg function, it might not work. (Formally, it was always
undefined behavior anyway, but an amazingly large amount of code
did it, and it worked anyway on a PDP-11.) So some of the
people working on PC's came up with using ((void*)0); the idea
being that the size NULL would automatically adjust to the size
of a pointer. The ISO C standard blessed this usage, along with
allowing implicit conversions both to AND from void* to any
other pointer type. (Most earlier C compilers simply allowed
assigning any int to a pointer.)

About the same time, C++ was gradually developing, but in the
environment where the original C (and not its MS-DOS derivates)
was widespread. In particular, void* was present in C++ before
it appeared in C, and it didn't convert implicitly to other
pointer types. NULL was defined as 0, and C++ introduced
special magic to allow 0 to convert to any pointer type. (Type
checking was much more rigorous in C++, from the very start.)

For whatever reasons, C++ never decided to extend this "magic"
to ((void*)0), so unlike in C, ((void*)0) is not a null pointer
constant in C++ (although it is a null pointer and a constant).
And except in the PC world, defining NULL as ((void*)0)
remainded an anomaly, even in C.

At any rate, the current best practice is to use NULL for the
null pointer constant if your compiler warns about misuse.
Opinions vary as to which is best if it doesn't; it probably
depends on how you code. (If you make heavy use of overloaded
functions and templates, the fact that NULL is in fact an
integer is likely to cause confusion. If you code simply and
straight forewardly, there's little risk of confusion, and NULL
better expresses your intent.) In neither case is the situation
really acceptable, and the committee has adopted a proposal for
a real nullptr, to be part of the next version of the standard.
 
J

James Kanze

[...]
I have an old C book. They write the following in this book:
free(head);
head = head->next;
I thought this can not work, because how can I free the "head" of the
list _at first_ without losing the whole list?

It's undefined behavior. It happened to work with some early
implementations. (In practice, it will work with a lot of
current implementations, at least in a single threaded
environment.) By chance. Don't do it.

The obvious correct way to do this is:

TKnoten* tmp = head->next ;
free( head ) ;
head = tmp ;
How can I iterate over the whole list then without an extra object?

Why do you need an extra object to iterate over the whole list?
My pre-standard DLList didn't have one. Type-checking is a bit
easier to manage if you have the extra object, but what I did
was define a basic node class, without any data, but with the
pointers, and then derive from that with the data. Something
like:

struct Node
{
Node* next ;
Node* prec ;
} ;

template< typename T >
struct ConcreteNode : public Node
{
T value ;
} ;

The DLList class contained a Node which served as root, so to
iterate, you'd do something like:

for ( Node* current = root.next ;
current != &root ;
current = current->next ) {
ConcreteNode< T >* p
= static_cast< ConcreteNode< T >* >( current ) ;
// ...
}

Alternatively, you can use special values in the pointers at the
end (NULL works fine), and keep separate head and tail pointers
in the List object, so iteration becomes:

for ( Node* current = first ;
current != NULL ;
current = current->next ) ...

This is perhaps easier to understand than using a circular list
with a dedicated node, but requires special casing for
insertions and deletions at either end.
 
B

BobR

James Kanze wrote in message...
On Jun 21, 8:51 am, "BobR" wrote:

/* """ quote ( said:
The 0 (zero) is one keypress, the NULL is five (if you count the shift-key).
[see the def below] It 'returns' a zero, so, why not just hit the '0' key?
int *pint( 0 );
vs.
int *pint( NULL );

That is the most stupid reason I've ever heard. You write code
to be read.

""" */ unquote

OH? Then why do so many (mis)use 'typedefs' to reduce typing?
If you are on line 27384 of some code and see "MyVec vec;", is it clear what
it's type/parms are? It's even worse in that case if the typedef is in a
header, now you need to open that header to find what it is.
Yeah, it's a weak argument, but since I use the 0 style, it's clear in my
logic.
I find it hard to believe that some seasoned C++ programmer would have
trouble understanding a zero. <G>

/* """
I'll take the first. Simple, and you don't have to chase down a macro or
documentation to know what it is.

NULL is part of the standard. You don't have to track down any
documentation to know what it is, any more than you do for
"int".
""" */

And we get how many posts a year asking about 'NULL'? :-}

int number( NULL ); // <G> ('newbie' mistake)
// C++, warning: initialization to non-pointer type `int' from NULL
// C ?.
std::cout<<number<<"\n";
// out: 0
[ Dang, now I don't know whether I'm arguing for or against 'NULL'! :-} ]


[snip]

/* """

There's a lot of historical issues floating around. Originally,
C didn't have void*, and 0 was the standard "null pointer
constant". This didn't change when void* was added to the
language, but in the MS-DOS world, the size of a pointer
depended on the compilation model (small, large, etc.), but the
size of an int didn't. This meant that if you passed NULL to a
vararg function, it might not work. (Formally, it was always
undefined behavior anyway, but an amazingly large amount of code
did it, and it worked anyway on a PDP-11.) So some of the
people working on PC's came up with using ((void*)0); the idea
being that the size NULL would automatically adjust to the size
of a pointer. The ISO C standard blessed this usage, along with
allowing implicit conversions both to AND from void* to any
other pointer type. (Most earlier C compilers simply allowed
assigning any int to a pointer.)

About the same time, C++ was gradually developing, but in the
environment where the original C (and not its MS-DOS derivates)
was widespread. In particular, void* was present in C++ before
it appeared in C, and it didn't convert implicitly to other
pointer types. NULL was defined as 0, and C++ introduced
special magic to allow 0 to convert to any pointer type. (Type
checking was much more rigorous in C++, from the very start.)

""" */

I think it was all those little differences in compilers that kept me in
Assembler 'till 2000 ( I used to call 'C' a "glorified librarian".). Again,
not a strong argument. I used 'a386' assembler because it accepted 'MASM'
syntax, but then along came 'NASM', another syntax to deal with. Intel? I
had trouble with their syntax. <G> 65c02, x86, 6800, 68000, mips,
AAAaaaagh!!! Help me, help me!!
So, when I saw that 'C++' had been standardised, I felt it would be worth a
look. Glad I did. If nothing else, the memory management made it worth
while.

It seems older 'C' coders prefer 'NULL'. I had no 'C' hangover, so I prefer
zero. <G> ( ...but then, I avoid pointers where I can. References! "int
&blah = nullptr;" == ouch!)

[snip rest of good info] Thanks.

Well, shall we let it go until next month where we get another 'newbie'
question on NULL? :-}
 
V

Victor Bazarov

BobR said:
[..]
And we get how many posts a year asking about 'NULL'? :-}

I dunno... Do you?
int number( NULL ); // <G> ('newbie' mistake)
// C++, warning: initialization to non-pointer type `int' from NULL
// C ?.

What C++ compiler gives such warning, could you be so kind to share?

I would expect a warning from C since in it 'NULL' can be defined as
((void*)0), but in C++ 'NULL' is just 0, so the initialisation (as the
compiler sees it) is

int number(0);

Now, wait until we have nullptr constant introduced into the language,
then we'll have more fun!
std::cout<<number<<"\n";
// out: 0
[ Dang, now I don't know whether I'm arguing for or against 'NULL'!
:-} ]

V
 
B

BobR

Victor Bazarov said:
BobR said:
[..]
And we get how many posts a year asking about 'NULL'? :-}

I dunno... Do you?

Millions, ....uuuh, I think I've seen at least 10. <G>
And one "what is 'int'?".
( ref: c.l.c++, a.c.l.l.c/c++. I seldom read *.moderated <hangs head in
shame>)
What C++ compiler gives such warning, could you be so kind to share?

My trusty (?) ol' GCC(MinGW)3.3.1. BUT, my TestBench program uses wxWidgets
(which accounted for 2/3 of the hits when searching for files containing
'NULL'.), so may be biased in some way.
Yeah, I was a little surprised too, very little.
I would expect a warning from C since in it 'NULL' can be defined as
((void*)0), but in C++ 'NULL' is just 0, so the initialisation (as the
compiler sees it) is

int number(0);

That was what I expected. but...
Actually, I think it was a great warning.
Now, wait until we have nullptr constant introduced into the language,
then we'll have more fun!

I'll use 'std::nullptr', without a squabble. [1]
Anyone figure a way to mis-use it yet? (let's give the newbies a preview!
<G>)

[1] - I think I have 'capitalizationphobia'. Someone chewed me out for
using all caps in a post back in '86, and I never recovered. <G> The BBSs
never complained about that (some required it (AppleII+)).
 
J

James Kanze

BobR said:
[..]
int number( NULL ); // <G> ('newbie' mistake)
// C++, warning: initialization to non-pointer type `int' from NULL
// C ?.
What C++ compiler gives such warning, could you be so kind to share?

G++. Has for the longest time.
I would expect a warning from C since in it 'NULL' can be defined as
((void*)0), but in C++ 'NULL' is just 0, so the initialisation (as the
compiler sees it) is
int number(0);

In C++, NULL must be defined as an "integral constant expression
evaluating to 0". It doesn't have to be 0; it can be "(1-1)",
"'\0'", or even "__builtin_special_0_which_triggers_warning".
All that is required is that it be an integral constant
expression, and that it have the value of 0.
Now, wait until we have nullptr constant introduced into the language,
then we'll have more fun!

I would think that that would reduce the discussion. The
current situation obviously isn't adequate: having a "null
pointer constant" that isn't allowed to be a pointer is a bit
wierd, to put it mildly; 0 is *not* an acceptable way of writing
a null pointer constant if the code is supposed to be readable,
and the fact that NULL expands to 0 makes it a lie, and causes
confusion in some cases. The need for an improvement is patent.
(FWIW: the authors of the proposal were Bjarne Stroustrup and
Herb Sutter, so it's got pretty good backing.)
std::cout<<number<<"\n";
// out: 0
[ Dang, now I don't know whether I'm arguing for or against 'NULL'!
:-} ]

The real problem is that writing 0 is misleading, but so is NULL
in certain cases:). Which one you prefer depends on which
confusion you consider the greater risk. If you're heavily into
templates, or do a lot of overloading, especially when
overloaded functions with the same name have different
semantics, you'll definitly prefer 0. If you tend to write
simple code, avoiding excess use of overloading and templates,
and are concerned about readability, you'll prefer NULL. In
neither case, however, will you be happy with the choice, since
in both cases, you'll be aware of the problems it causes.
 

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

No members online now.

Forum statistics

Threads
474,292
Messages
2,571,494
Members
48,179
Latest member
รับปั๊มไลค์|LikePro

Latest Threads

Top