By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,197 Members | 1,057 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,197 IT Pros & Developers. It's quick & easy.

Strings with Templates not working?

P: n/a
Hello,

I'm using a template to simulate a LinkedList from Java.It works without
problems, but when I want to use strings in main.cpp instead of char*, I
get the following error message:

$ ./Main
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct NULL not valid

I tried to import <stringboth in main.cpp and listT.h, but the
errormsg was the same.

The classes look like this:

MAIN.CPP------------------------------------------
#include "ListT.h"
#include <iostream>

using namespace std;

int main(void) {

ListT<string*testList = new ListT<string>();
testList->add("Test1");
testList->add("Test2");
testList->add("Test3");
cout << testList->get(0) <<endl;
cout << testList->get(1) <<endl;
cout << testList->get(2) <<endl;
delete testList;

return 0;
}
------------------------------------------------

LISTT.H-----------------------------------------

template <class Tclass ListT {

private:
struct TKnoten {
T daten;
int index;
TKnoten *next;
};
int counter;
TKnoten *kopf;

public:
ListT();
virtual ~ListT();
void add(T element);
//void remove(T element);
T get(int i);
};

template <class T>
ListT<T>::ListT() {
counter = 0;
kopf = new TKnoten();
kopf->next = 0;
}

template <class T>
ListT<T>::~ListT() {
while (kopf->next != 0) {
TKnoten *previous = new TKnoten();
previous = kopf;
kopf = kopf->next;
delete previous;
}
delete kopf;
}

template <class T>
void ListT<T>::add(T element) {
TKnoten *newKnoten = new TKnoten();

newKnoten->next = kopf;
kopf = newKnoten;
kopf->daten = element;
kopf->index = counter;
counter++;
}

template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = new TKnoten();
T daten = 0;
iterator = kopf;
while (iterator->next != 0) {
if (iterator->index == i) {
daten = iterator->daten;
}
iterator = iterator->next;
}
delete iterator;
return daten;
}

What's wrong with string as type? I'm using Linux with gcc (g++),
Thanks for your answers,

Markus
Jun 20 '07 #1
Share this Question
Share on Google+
31 Replies


P: n/a
On Wed, 20 Jun 2007 21:41:13 +0200, Markus Pitha wrote:
Hello,

I'm using a template to simulate a LinkedList from Java.It works without
problems, but when I want to use strings in main.cpp instead of char*, I
get the following error message:

$ ./Main
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct NULL not valid

I tried to import <stringboth in main.cpp and listT.h, but the
errormsg was the same.

The classes look like this:
[snip]
template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = new TKnoten();
T daten = 0;
!---->>^^^^^^^^^^^

T daten = "";

iterator = kopf;
while (iterator->next != 0) {
if (iterator->index == i) {
daten = iterator->daten;
}
iterator = iterator->next;
}
delete iterator;
return daten;
}

What's wrong with string as type? I'm using Linux with gcc (g++),
--
Obnoxious User
Jun 20 '07 #2

P: n/a
On Jun 20, 2:41 pm, Markus Pitha <newsgroupsNOS...@pithax.netwrote:
template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = new TKnoten();
T daten = 0;
Pretty sure this is your problem. You're assigning NULL to a string
object.

I know this isn't your question, but you know that C++ already comes
with a linked list right? And also, it may have been better style to
declare your list on the stack instead of as a pointer and then using
new / delete. You may be aware of this already, but from your post it
sounds like you come from a Java background, where everything is just
new new new allocated on the heap.

Jun 20 '07 #3

P: n/a
On Wed, 20 Jun 2007 19:37:49 +0000, Obnoxious User wrote:
On Wed, 20 Jun 2007 21:41:13 +0200, Markus Pitha wrote:
>Hello,

I'm using a template to simulate a LinkedList from Java.It works without
problems, but when I want to use strings in main.cpp instead of char*, I
get the following error message:

$ ./Main
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct NULL not valid

I tried to import <stringboth in main.cpp and listT.h, but the
errormsg was the same.

The classes look like this:
[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;
>
> iterator = kopf;
while (iterator->next != 0) {
if (iterator->index == i) {
daten = iterator->daten;
}
iterator = iterator->next;
}
delete iterator;
return daten;
}

What's wrong with string as type? I'm using Linux with gcc (g++),
--
Obnoxious User
Jun 20 '07 #4

P: n/a
Markus Pitha wrote:
Hello,

I'm using a template to simulate a LinkedList from Java.It works
without problems, but when I want to use strings in main.cpp instead
of char*, I get the following error message:

$ ./Main
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct NULL not valid

I tried to import <stringboth in main.cpp and listT.h, but the
errormsg was the same.
You have some logical errors in your code. See below.
>
The classes look like this:

MAIN.CPP------------------------------------------
#include "ListT.h"
#include <iostream>

using namespace std;

int main(void) {

ListT<string*testList = new ListT<string>();
testList->add("Test1");
testList->add("Test2");
testList->add("Test3");
cout << testList->get(0) <<endl;
cout << testList->get(1) <<endl;
cout << testList->get(2) <<endl;
delete testList;

return 0;
}
------------------------------------------------

LISTT.H-----------------------------------------

template <class Tclass ListT {

private:
struct TKnoten {
T daten;
int index;
TKnoten *next;
The 'TKnoten' struct is not a POD, which means that upon its
default-initialisation both 'index' and 'next' contain garbage.
You should write a default c-tor which will initialise 'index'
to something specific, like -1, and 'next' to NULL.
};
int counter;
TKnoten *kopf;

public:
ListT();
virtual ~ListT();
void add(T element);
//void remove(T element);
T get(int i);
};

template <class T>
ListT<T>::ListT() {
counter = 0;
kopf = new TKnoten();
kopf->next = 0;
}

template <class T>
ListT<T>::~ListT() {
while (kopf->next != 0) {
TKnoten *previous = new TKnoten();
previous = kopf;
Take a close look at the previous two statements. You create
a new 'TKnoten' object, obtain a pointer to it and IMMEDIATELY
lose it by overriding the value in 'previous'. Do you really
need to create a new 'TKnoten' here while deleting your list?
kopf = kopf->next;
delete previous;
}
delete kopf;
}

template <class T>
void ListT<T>::add(T element) {
TKnoten *newKnoten = new TKnoten();

newKnoten->next = kopf;
kopf = newKnoten;
kopf->daten = element;
kopf->index = counter;
counter++;
}

template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = new TKnoten();
HUH? Why are you creating another 'TKnoten' here?
T daten = 0;
iterator = kopf;
Again, you're immediately losing the value of 'iterator' that you
just obtained from 'new'...
while (iterator->next != 0) {
if (iterator->index == i) {
daten = iterator->daten;
}
iterator = iterator->next;
}
delete iterator;
Are you sure you need to 'delete' it here?
return daten;
}

What's wrong with string as type? I'm using Linux with gcc (g++),
Nothing is wrong with string as type. Several things are wrong with
your program, however. The main thing I'd look closely into would
be the 'delete iterator' in the 'get' member function.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 20 '07 #5

P: n/a
Hello,

Obnoxious User wrote:
> T daten = 0;
!---->>^^^^^^^^^^^
Ah, I see. That's it.
By the way, why do I have to include <stringfor using NULL?
At first, I thought I have to define NULL like this #define NULL (void*)
0 but I got some error about redefining null.
By coincidence, I found out that NULL is in string.

Markus
Jun 20 '07 #6

P: n/a
Zachary Turner wrote:
I know this isn't your question, but you know that C++ already comes
with a linked list right? And also, it may have been better style to
declare your list on the stack instead of as a pointer and then using
new / delete.
Where can I find this linked list? In the internet, I only find
tutorials how to create a linked list.
Which benefits does it have to create it on the stack?
I thought that dynamically allocated space would be better.


Jun 20 '07 #7

P: n/a
Victor Bazarov schrieb:
Markus Pitha wrote:
>Hello,

I'm using a template to simulate a LinkedList from Java.It works
without problems, but when I want to use strings in main.cpp instead
of char*, I get the following error message:

$ ./Main
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct NULL not valid

I tried to import <stringboth in main.cpp and listT.h, but the
errormsg was the same.

You have some logical errors in your code. See below.
>The classes look like this:

MAIN.CPP------------------------------------------
#include "ListT.h"
#include <iostream>

using namespace std;

int main(void) {

ListT<string*testList = new ListT<string>();
testList->add("Test1");
testList->add("Test2");
testList->add("Test3");
cout << testList->get(0) <<endl;
cout << testList->get(1) <<endl;
cout << testList->get(2) <<endl;
delete testList;

return 0;
}
------------------------------------------------

LISTT.H-----------------------------------------

template <class Tclass ListT {

private:
struct TKnoten {
T daten;
int index;
TKnoten *next;

The 'TKnoten' struct is not a POD, which means that upon its
default-initialisation both 'index' and 'next' contain garbage.
You should write a default c-tor which will initialise 'index'
to something specific, like -1, and 'next' to NULL.
Ok.
Take a close look at the previous two statements. You create
a new 'TKnoten' object, obtain a pointer to it and IMMEDIATELY
lose it by overriding the value in 'previous'. Do you really
need to create a new 'TKnoten' here while deleting your list?
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?
>
> kopf = kopf->next;
delete previous;
}
delete kopf;
}

template <class T>
void ListT<T>::add(T element) {
TKnoten *newKnoten = new TKnoten();

newKnoten->next = kopf;
kopf = newKnoten;
kopf->daten = element;
kopf->index = counter;
counter++;
}

template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = new TKnoten();

HUH? Why are you creating another 'TKnoten' here?
How can I iterate over the whole list then without an extra object?

> T daten = 0;
iterator = kopf;

Again, you're immediately losing the value of 'iterator' that you
just obtained from 'new'...
> while (iterator->next != 0) {
if (iterator->index == i) {
daten = iterator->daten;
}
iterator = iterator->next;
}
delete iterator;

Are you sure you need to 'delete' it here?
I thought that I have to delete everything I allocated with "new"?

Markus
Jun 20 '07 #8

P: n/a
On Wed, 20 Jun 2007 22:19:16 +0200, Markus Pitha wrote:
Zachary Turner wrote:
>I know this isn't your question, but you know that C++ already comes
with a linked list right? And also, it may have been better style to
declare your list on the stack instead of as a pointer and then using
new / delete.

Where can I find this linked list? In the internet, I only find
tutorials how to create a linked list.
#include <list>
#include <iostream>
int main() {
std::list<intlist;
list.push_back(0);
list.push_back(1);
list.push_back(2);

std::cout<<"front: "<<list.front()<<std::endl;
std::cout<<"back: "<<list.back()<<std::endl;
std::cout<<"complete: ";
std::list<int>::iterator ii = list.begin();
while(true) {
std::cout<<*ii;
if(++ii == list.end()) break;
std::cout<<",";
}
std::endl(std::cout);
return 0;
}

--
Obnoxious User
Jun 20 '07 #9

P: n/a
On Jun 20, 3:19 pm, Markus Pitha <newsgroupsNOS...@pithax.netwrote:
Zachary Turner wrote:
I know this isn't your question, but you know that C++ already comes
with a linked list right? And also, it may have been better style to
declare your list on the stack instead of as a pointer and then using
new / delete.

Where can I find this linked list? In the internet, I only find
tutorials how to create a linked list.
Which benefits does it have to create it on the stack?
I thought that dynamically allocated space would be better.
#include <list>
using namespace std;

int main()
{
list<intmylist;
mylist.push_back(1);
mylist.push_back(2);
mylist.push_back(3);
}

If you take this approach, there is a bit of a learning curve you will
have to overcome. Some keywords you can use to search for related
topics are:

STL (Standard Template Library) - a collection of generic containers
and algorithms provided with C++)
std::list - One of the generic collections in the STL. It's a doubly
linked list, and supports any time
iterator - The STL paradigm for iterating over any and all collections
in the STL.


Regarding memory allocation, stack based and heap based memory
allocation is totally separate.

Heap based - You specify exactly when it is created (with new), NULL
value is possible, and you specify exactly when it is deleted (with
delete)

Stack based - It is created the instant it is declared, NULL is not
possible, it is deleted immediately when it goes out of scope.
Consider this code:

if (true)
{
list<int>* pList = new list<int>();

pList->push_back(1);

delete pList;
}

Here you create a new instance of list immediately when you declare
it. You never make use of the null value, and you delete it
immediately before it goes out of scope. This is equivalent to what
stack based allocation provides. Therefore, the code is equivalent
to:

if (true)
{
list<intlist;
list.push_back(1);
}
Jun 20 '07 #10

P: n/a
Markus Pitha wrote:
Victor Bazarov schrieb:
>Markus Pitha wrote:
>>[..]
template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = new TKnoten();

HUH? Why are you creating another 'TKnoten' here?

How can I iterate over the whole list then without an extra object?
That's a strange question. When you need to look for something in
your desk drawers, do you go out an buy another drawer? When you
need to look for something in some text files on your hard drive,
do you first create another file? No, you just open them, look in
them, and move on.

To iterate over objects that exist in your list, all you need is
a pointer where you will store the address of the existing objects.
There is no need to create another object to immediately lose its
address because you assign 'kopf' to 'iterator' two lines down.
>
>> T daten = 0;
iterator = kopf;

Again, you're immediately losing the value of 'iterator' that you
just obtained from 'new'...
>> while (iterator->next != 0) {
if (iterator->index == i) {
daten = iterator->daten;
}
iterator = iterator->next;
}
delete iterator;

Are you sure you need to 'delete' it here?

I thought that I have to delete everything I allocated with "new"?
Yes, but *what* are you deleting? It would seem to me that you
are actually deleting the last element of the list...

You should undoubtedly attempt to write your own linked list at some
point in your studies. But you need to pay attention to what you're
doing.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 20 '07 #11

P: n/a
Markus Pitha wrote:
Zachary Turner wrote:
>I know this isn't your question, but you know that C++ already comes
with a linked list right? And also, it may have been better style to
declare your list on the stack instead of as a pointer and then using
new / delete.

Where can I find this linked list? In the internet, I only find
tutorials how to create a linked list.
Which benefits does it have to create it on the stack?
I thought that dynamically allocated space would be better.
In your favorite C++ programming book. Or google for "c++ standard library"
(also known as "standard template library").

#include <iostream>
#include <string>
#include <list>

int main()
{
using std::list;
using std::string;

list<stringmylist;

mylist.push_back("One");
mylist.push_back("Two");

for (list<string>::iterator itor = mylist.begin(); itor != mylist.end();
itor++)
std::cout << *itor << std::endl;
}

In C++, it is generally better to use objects with automatic storage
duration (generally created on the stack), and use dynamic allocation only
when necessary. The problem with dynamically allocated objects is that you
have to handle the deletion manually.

--
Thomas
http://www.netmeister.org/news/learn2quote.html
Jun 20 '07 #12

P: n/a
On Jun 20, 3:27 pm, Markus Pitha <newsgroupsNOS...@pithax.netwrote:
while (iterator->next != 0) {
if (iterator->index == i) {
daten = iterator->daten;
}
iterator = iterator->next;
}
delete iterator;
Are you sure you need to 'delete' it here?

I thought that I have to delete everything I allocated with "new"?
I think the real issue is that you should never have 'new'd anything
in the first place. All the memory required for this operation has
already been allocated. This is just a get function. The object
already exists, you just want to get it. A more correct get()
function would look like this:

template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = kopf;

while (iterator->next != NULL) {
if (iterator->index == i) {
return iterator->daten;
}
}
return ??; //Need to decide what to return here that means "not
found". Probably a design issue though.
}

Jun 20 '07 #13

P: n/a
Thanks again for all your tips.
I'll take it to heart.

Markus
Jun 20 '07 #14

P: n/a
Victor Bazarov wrote:
Markus Pitha wrote:
>Victor Bazarov schrieb:
>>Markus Pitha wrote:
[..]
template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = new TKnoten();
HUH? Why are you creating another 'TKnoten' here?
How can I iterate over the whole list then without an extra object?

That's a strange question. When you need to look for something in
your desk drawers, do you go out an buy another drawer? When you
need to look for something in some text files on your hard drive,
do you first create another file? No, you just open them, look in
them, and move on.
When I don't instance a new object, I get memory access errors while
executing the file.

Jun 20 '07 #15

P: n/a
Markus Pitha <ne**************@pithax.netwrote in news:61bd8$46798a1d
$5*************@news.chello.at:
Hello,

Obnoxious User wrote:
>> T daten = 0;
!---->>^^^^^^^^^^^

Ah, I see. That's it.
By the way, why do I have to include <stringfor using NULL?
At first, I thought I have to define NULL like this #define NULL (void*)
0 but I got some error about redefining null.
By coincidence, I found out that NULL is in string.
IIRC: NULL is properly defined in <cstddef>. And if you must define NULL
yourself, it should be:

#define NULL 0

Or, Stroustrup suggests:

const int NULL = 0;
You don't want the (void *) in there.
Jun 20 '07 #16

P: n/a
Markus Pitha wrote:
Victor Bazarov wrote:
>Markus Pitha wrote:
>>Victor Bazarov schrieb:
Markus Pitha wrote:
[..]
template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = new TKnoten();
HUH? Why are you creating another 'TKnoten' here?
How can I iterate over the whole list then without an extra object?

That's a strange question. When you need to look for something in
your desk drawers, do you go out an buy another drawer? When you
need to look for something in some text files on your hard drive,
do you first create another file? No, you just open them, look in
them, and move on.

When I don't instance a new object, I get memory access errors while
executing the file.
I am not sure I understand. How did you arrive at the conclusion that
you need to allocate another object to fix the memore access errors?
And I bet you the memore access errors are actually due to the 'delete'
you have there without merit.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 20 '07 #17

P: n/a
Victor Bazarov wrote:
I am not sure I understand. How did you arrive at the conclusion that
you need to allocate another object to fix the memore access errors?
And I bet you the memore access errors are actually due to the 'delete'
you have there without merit.
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;
}
delete kopf;
}

For testing, I wrote an int to stdout as often as the while loop runs. I
get 3 outputs (as much as I have(had) elements).
For me that means, that the list is not lost, but why does that work?

Markus

Jun 20 '07 #18

P: n/a
On Jun 20, 4:09 pm, Markus Pitha <newsgroupsNOS...@pithax.netwrote:
When I don't instance a new object, I get memory access errors while
executing the file.
Imagine this were a different language like Java. Would you write the
following code?

int get()
{
TKnoten iterator = new TKnoten();

while ((iterator = list->next()) != null)
{
//do something with iterator
}
}

certainly not. You would do this:

int get()
{
TKnoten iterator = null;

while ((iterator = list->next()) != null)
{
//do something with iterator
}
}

My personal advice is to study the basics of pointers and dynamic/
static memory allocation some more. The problem you are trying to
solve, while not terribly difficult, combines a lot of concepts that
it seems you're trying to jump into without first having a fundamental
understanding of pointers and memory.

Jun 20 '07 #19

P: n/a
Andre Kostur wrote:
IIRC: NULL is properly defined in <cstddef>. And if you must define NULL
yourself, it should be:

#define NULL 0

Or, Stroustrup suggests:
const int NULL = 0;
You don't want the (void *) in there.
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.
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.

Markus

Jun 20 '07 #20

P: n/a
Markus Pitha <ne**************@pithax.netwrote in
news:51***************************@news.chello.at:
Andre Kostur wrote:
>IIRC: NULL is properly defined in <cstddef>. And if you must define
NULL yourself, it should be:

#define NULL 0

Or, Stroustrup suggests:
> const int NULL = 0;
>You don't want the (void *) in there.

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.
Jun 20 '07 #21

P: n/a
On Wed, 20 Jun 2007 19:42:05 +0000, Obnoxious User wrote:
On Wed, 20 Jun 2007 19:37:49 +0000, Obnoxious User wrote:
>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.

--
Markus Schoder
Jun 20 '07 #22

P: n/a
Markus Pitha <ne**************@pithax.netwrote in news:8fa7a$46799d03
$5*************@news.chello.at:
Victor Bazarov wrote:
>I am not sure I understand. How did you arrive at the conclusion that
you need to allocate another object to fix the memore access errors?
And I bet you the memore access errors are actually due to the
'delete'
>you have there without merit.

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;
}
Jun 20 '07 #23

P: n/a
Andre Kostur wrote:
How about:

template <class T>
ListT<T>::~ListT() {
while (kopf->next != NULL) {
while (kopf) {
TKnoten * toDelete = kopf;
kopf = kopf->next;
delete toDelete;
}
delete kopf;
Remove this.
}
--
Thomas
http://www.netmeister.org/news/learn2quote.html
Jun 20 '07 #24

P: n/a

Andre Kostur <nn******@kostur.netwrote in message...
Markus Pitha <ne**************@pithax.netwrote in
Andre Kostur wrote:
IIRC: NULL is properly defined in <cstddef>. And if you must define
NULL yourself, it should be:

#define NULL 0

Or, Stroustrup suggests:
const int NULL = 0;
You don't want the (void *) in there.
You were right. It works with cstddef.
But I don't understand yet why NULL is frowned upon in C++.
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.

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.
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

--
Bob R
POVrookie
Jun 21 '07 #25

P: n/a
On Jun 20, 11:38 pm, Markus Pitha <newsgroupsNOS...@pithax.netwrote:
Andre Kostur wrote:
IIRC: NULL is properly defined in <cstddef>. And if you must define NULL
yourself, it should be:
#define NULL 0
Or, Stroustrup suggests:
const int NULL = 0;
You don't want the (void *) in there.
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.

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 21 '07 #26

P: n/a
On Jun 21, 8:51 am, "BobR" <removeBadB...@worldnet.att.netwrote:
Andre Kostur <nntps...@kostur.netwrote 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 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.
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.

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 21 '07 #27

P: n/a
On Jun 20, 10:27 pm, Markus Pitha <newsgroupsNOS...@pithax.netwrote:

[...]
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 ;
template <class T>
T ListT<T>::get(int i) {
TKnoten *iterator = new TKnoten();
HUH? Why are you creating another 'TKnoten' here?
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.

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 21 '07 #28

P: n/a

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

/* """ quote (<Ghere we go again! <G>)
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. <G65c02, 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? :-}

--
Bob R
POVrookie
Jun 21 '07 #29

P: n/a
BobR wrote:
[..]
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
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 21 '07 #30

P: n/a

Victor Bazarov <v.********@comAcast.netwrote in message
news:f5**********@news.datemas.de...
BobR wrote:
[..]
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>)
>
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?
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. <GThe BBSs
never complained about that (some required it (AppleII+)).
--
Bob R
POVrookie
Jun 21 '07 #31

P: n/a
On Jun 21, 9:02 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
BobR wrote:
[..]
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.

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 22 '07 #32

This discussion thread is closed

Replies have been disabled for this discussion.