Good links for handling with pointers?

M

Markus Pitha

Hello,

I still have massive problems with handling with pointers when I use
them through methods or much more complicated constructs.
Do you have any good and helpful links which describe these issues
carefully?

Thanks,
Markus
 
A

Alf P. Steinbach

* Markus Pitha:
Hello,

I still have massive problems with handling with pointers when I use
them through methods or much more complicated constructs.
Do you have any good and helpful links which describe these issues
carefully?

Exactly what is the problem?
 
M

Markus Pitha

Hello,
Exactly what is the problem?

I often get "segmentation fault" errors because with catchier
constructs, I'm not sure anymore if I should use a reference or a
pointer an so on.
Then often I have the problem that I have a method which should obtain a
non pointer variable, but in this case I only have a pointer to this
variable, and what then?

Let's see my actual example which leads to a "segemntation fault" or
doesn't even compile:

----------------------------------------------------

class Adjazenzmatrix
--------------------
..
..
..
Knoten *knoten[groesse]; //I define a list of size "groesse" of pointers
to "Knoten".

for (int i = 0; i < groesse; i++) {
knoten = new Knoten(i); initialize every element as new Knoten
..
..
..//and so on.....

//This is weird. Here I want to iterate over every element of "knoten",
but....

for (int kBez = 0; kBez < groesse; kBez++) {
findKomponenten(knoten[kBez]); //LINE 178
}
}
-------------------------------------------

....I get the following error message while compiling:

markus@gentoo ~/CPP-Programme/ $ g++ *.cpp -o Main `pkg-config gtkmm-2.4
--cflags --libs`
Adjazenzmatrix.cpp: In member function »void
Adjazenzmatrix::berechneEigenschaften()«:
Adjazenzmatrix.cpp:178: Fehler: ungültige Umwandlung von »Knoten*« in »int«
Adjazenzmatrix.cpp:178: Fehler: Argument 1 von »Knoten::Knoten(int)«
wird initialisiert

Which means something like:
Invalid conversion of "Knoten*" to "int.
Error: Argument 1 of Knoten::Knoten(int) will be initialized.

What does that mean?

Here is the method findKomponenten:
-------------------------------------------------
void Adjazenzmatrix::findKomponenten(Knoten k) {
k.setVisited();
if (k.getNachbarknotenAnzahl() > 0) {
int nachbarCounter = 0;
Knoten neuer = k.getNachbarknoten(nachbarCounter);
while (neuer.isVisited() == false) {
findKomponenten(neuer);
nachbarCounter++;
}
}
}
-------------------------------------------------
So where is there an int I obviously convert to?

Constructor of class Knoten:
------------------------------------------
Knoten::Knoten(int nr) {
knotenNr = nr;
visited = false;
nachbarknoten = new ListT<Knoten>;
}

As you can see, I use a self programmed dynamically list in this class.
Now it's getting complicated for me. Later in this class, I initialize
new ListT-elements which are also "Knoten". I want to access those
elements from Adjazenzmatrix so I have sometimes already pointer with
the deep of two and then I'm not sure anymore how to handle it.
I don't know if I should return a pointer or not or as I already said,
the return values doesn't "fit" to the class which invokes the methods
of the instances because the method returns a non pointer value but in
the invoking class I have a pointer.
I alwasy fight with such problems, so I need to get deeper into the
knowledge of handling with pointer.


Markus
 
A

Alf P. Steinbach

* Markus Pitha:
Hello,
Exactly what is the problem?

I often get "segmentation fault" errors because with catchier
constructs, I'm not sure anymore if I should use a reference or a
pointer an so on.
Then often I have the problem that I have a method which should obtain a
non pointer variable, but in this case I only have a pointer to this
variable, and what then?

Let's see my actual example which leads to a "segemntation fault" or
doesn't even compile:

----------------------------------------------------

class Adjazenzmatrix
--------------------
.
.
.
Knoten *knoten[groesse]; //I define a list of size "groesse" of pointers
to "Knoten".

Use a std::vector instead of a raw array.

Use boost::shared_ptr instead of raw pointers.


for (int i = 0; i < groesse; i++) {
knoten = new Knoten(i); initialize every element as new Knoten
.
.
.//and so on.....

//This is weird. Here I want to iterate over every element of "knoten",
but....

for (int kBez = 0; kBez < groesse; kBez++) {
findKomponenten(knoten[kBez]); //LINE 178
}
}
-------------------------------------------

...I get the following error message while compiling:

markus@gentoo ~/CPP-Programme/ $ g++ *.cpp -o Main `pkg-config gtkmm-2.4
--cflags --libs`
Adjazenzmatrix.cpp: In member function »void
Adjazenzmatrix::berechneEigenschaften()«:
Adjazenzmatrix.cpp:178: Fehler: ungültige Umwandlung von »Knoten*« in »int«
Adjazenzmatrix.cpp:178: Fehler: Argument 1 von »Knoten::Knoten(int)«
wird initialisiert

Which means something like:
Invalid conversion of "Knoten*" to "int.
Error: Argument 1 of Knoten::Knoten(int) will be initialized.

What does that mean?


It means you're supplying a pointer to a Knoten instance where a Knoten
instance is required. The compiler tries to convert the pointer to an
instance by passing it to a Knoten constructor that expects an int
argument. The pointer cannot, however, be converted to int.

What you can do is to dereference the pointer:

findKomponenten( *(knoten[kBes]) );


Here is the method findKomponenten:
-------------------------------------------------
void Adjazenzmatrix::findKomponenten(Knoten k) {
k.setVisited();
if (k.getNachbarknotenAnzahl() > 0) {
int nachbarCounter = 0;
Knoten neuer = k.getNachbarknoten(nachbarCounter);
while (neuer.isVisited() == false) {
findKomponenten(neuer);
nachbarCounter++;
}
}
}

Right below.

Constructor of class Knoten:
------------------------------------------
Knoten::Knoten(int nr) {
knotenNr = nr;
visited = false;
nachbarknoten = new ListT<Knoten>;
}

As you can see, I use a self programmed dynamically list in this class.

Just use std::list instead.

Now it's getting complicated for me. Later in this class, I initialize
new ListT-elements which are also "Knoten". I want to access those
elements from Adjazenzmatrix so I have sometimes already pointer with
the deep of two and then I'm not sure anymore how to handle it.
I don't know if I should return a pointer or not or as I already said,
the return values doesn't "fit" to the class which invokes the methods
of the instances because the method returns a non pointer value but in
the invoking class I have a pointer.
I alwasy fight with such problems, so I need to get deeper into the
knowledge of handling with pointer.

Instead, what you probably need most is to discover that the standard
library's collection classes solve most of the problems you're
struggling with.

Some pointer usage will remain.

For that, use smart pointers such as boost::shared_ptr so that you don't
have to struggle with deallocation and invalid pointers and so on.


Cheers, & hth.,

- Alf
 
M

Markus Pitha

Hello,

you are surely right when you say that I'd rather use these libraries.
But my target is it to improve my C++ skills. I think that perfect
handling with pointers is one of the basics if someone wants to cope
with C or C++. And I think that my pointer knowledge is still insufficient.


Markus
 
K

Kai-Uwe Bux

Markus said:
Hello,

you are surely right when you say that I'd rather use these libraries.
But my target is it to improve my C++ skills. I think that perfect
handling with pointers is one of the basics if someone wants to cope
with C or C++. And I think that my pointer knowledge is still
insufficient.

Uhm, handling of dynamic allocation is hardly one of the _basics_. It is a
necessary skill, that much is true. And pointers are part of the core
language. However, I think that acquirering pointer skills should come
somewhat late in the learning process. The reason is that proper dynamic
allocation and deallocation requires awareness of many traps created by
their interaction with other parts of the language, most notably
try-throw-catch. If you dive into these issues early, you may pick up
habits that are dangerous but whose dangers can only be seen from a more
advanced perspective.

A fundamental rule for dynamic allocation is that each allocation has to be
matched by one and only one deallocation along _each_ possible path of
execution. This requires a somewhat global perspective on your code. You
cannot verify this property by looking at your code locally. Since a throw
hidden in a function can divert the path of execution at any given moment,
this is very hard to ensure.

For starters, you should stick to the rule that allocation of pointers is
done in a constructor and the matching deallocation goes into the code of
the destructor. That will ensure proper matching of allocation and
deallocation (unless the constructor throws after an allocation:).

Another hint is: use debugging tools like valgrind to check all your
programs for memory correctness. Dereferencing dangling pointers is
undefined behavior and does not always show as a crash.


Anyway, the most important knowledge about dynamic allocation is the many
ways of using the STL instead.


Best

Kai-Uwe Bux
 
M

Markus Pitha

Hello,

acutally I'm not a total beginner with pointers but my current problem
annoys me, so I'm not experienced enough. It is obvious that I won't
come to a conclusion for now and I decided to rewrite the non working
parts of my program with STL. Maybe it's getting clearer for me then.

Markus
 
J

James Kanze

[...]
Use boost::shared_ptr instead of raw pointers.

That's bad advice, generally. There are cases where
boost::shared_ptr is appropriate, but there are lots of cases
where it isn't. Expecting it to solve all of your problems will
only lead to more problems.

[...]
Instead, what you probably need most is to discover that the standard
library's collection classes solve most of the problems you're
struggling with.
Some pointer usage will remain.

And most of it will be navigation. Where boost::shared_ptr
isn't appropriate.
For that, use smart pointers such as boost::shared_ptr so that
you don't have to struggle with deallocation and invalid
pointers and so on.

If the only problem is deallocation, the Boehm garbage collector
is a much simpler solution than boost::shared_ptr. But neither
it nor boost::shared_ptr can protect you from all pointer
errors---in particular, it's remarkably easy to get an invalid
pointer in C++ if you start with the address of an object with
automatic lifetime. And even with dynamically allocated
objects, the fact that the memory for the object hasn't been
freed doesn't guarantee the object's validity.

The problem with pointers is that they are a low level concept,
used to implement several different high level concepts.
Logically, you might argue that you need a different type of
smart pointer for each high level concept, but in practice, the
wrapper in many cases would be so thin that it's not worth the
bother. (Or maybe it is, for beginners. Just turning off
pointer arithmetic, for example, which probably shouldn't be
used in modern C++ unless you're implementing something like
std::vector.)

Just systematically replacing all raw pointers with
boost::shared_ptr, however, is almost guaranteed to get you into
trouble.
 
J

James Kanze

Uhm, handling of dynamic allocation is hardly one of the _basics_.

It depends on what you're doing. It's certainly basic to the
applications I work on: a client connects, and creates an
order---where'm I going to put it, if not in dynamic memory? On
the other hand, in such applications, handling dynamic
allocation is usually pretty trivial as well. When the order
has been fully processed, it removes itself from the order table
(actually a hash map) and delete's itself.

I'd also expect even a relative neophyte to be able to implement
simple dynamic data structures, like double linked lists.
It is a necessary skill, that much is true. And pointers are
part of the core language. However, I think that acquirering
pointer skills should come somewhat late in the learning
process.

Late, as compared to what? I'd teach pointers before exceptions
or writing (as opposed to usiing) templates. I'd probably teach
them before inheritance, virtual functions, and the rest.

On the other hand, I'd probably not teach everything about them
at that point.

[...]
Anyway, the most important knowledge about dynamic allocation
is the many ways of using the STL instead.

Not all of the ways. I'd certainly present std::vector and
std::string before pointers. I'd probably even present
iterators and algorithms, although I'm not sure. But I can't
quite seem teaching someone how to write and STL iterator before
he understands pointer basics.

I think that pointers (like the STL) need to be handled at
several different levels. Some basic uses should appear fairly
early, where as some of the most subtle parts probably aren't
ever needed by the average programmer.
 
K

Kai-Uwe Bux

James said:
It depends on what you're doing. It's certainly basic to the
applications I work on: a client connects, and creates an
order---where'm I going to put it, if not in dynamic memory? On
the other hand, in such applications, handling dynamic
allocation is usually pretty trivial as well. When the order
has been fully processed, it removes itself from the order table
(actually a hash map) and delete's itself.

The STL offers a good deal of dynamic data structures that allow you to have
data in dynamic memory without new()-ing them yourself. In teaching C++, I
would first discuss the standard containers before I dive into new() and
delete(). (In fact, I would be inclined to discuss new() and delete() in
the context of implementing containers.)

I'd also expect even a relative neophyte to be able to implement
simple dynamic data structures, like double linked lists.

I don't. I would rather expect the implementation of a relative neophyte to
contain subtle bugs like leaking memory when copy-constructors throw. The
cumbersome issue will be that the neophyte will not even be able to see
those issues.

Late, as compared to what? I'd teach pointers before exceptions
or writing (as opposed to usiing) templates.

Here, I strongly disagree. I would definitely discuss try-throw-catch before
diving into dynamic allocation issues. The reasons are in the part of my
previous post that you snipped.

I'd probably teach them before inheritance, virtual functions, and the
rest.

You have a valid point here: The whole OO business needs pointers to
actually model the subclass thing (aka is-a-relationship). If D is derived
from B, it is not really true that values of type D form a subset of values
of type B. The map from

Values(D) --> Values(B)

is a projection called slicing. On the other hand, the map

Values(D*) --> Values(B*)

is an honest inclusion: every D* is a B*.

Now the question is whether that observation implies that pointers should
come early or whether the right conclusion is that OO should come late. I
strongly sympathize with the later point of view. However, teaching C++
very likely is not done just to master the language, but to master specific
tasks of programming (i.e., there are outside constraints and interests
involved). I am willing to acknowledge that given such constraints, OO
might even be the primary focus of the class, in which case pointers will
have to come very early.

On the other hand, I'd probably not teach everything about them
at that point.

[...]
Anyway, the most important knowledge about dynamic allocation
is the many ways of using the STL instead.

Not all of the ways. I'd certainly present std::vector and
std::string before pointers. I'd probably even present
iterators and algorithms, although I'm not sure. But I can't
quite seem teaching someone how to write and STL iterator before
he understands pointer basics.

Teaching how to write an STL conforming iterator is different from teaching
using the STL. I certainly would like the student to see
I think that pointers (like the STL) need to be handled at
several different levels. Some basic uses should appear fairly
early, where as some of the most subtle parts probably aren't
ever needed by the average programmer.

I am a little worried about the basic uses getting the student into bad
habits that are hard to correct later.


Best

Kai-Uwe Bux
 
A

Alf P. Steinbach

* James Kanze:
[...]
Use boost::shared_ptr instead of raw pointers.

That's bad advice, generally. There are cases where
boost::shared_ptr is appropriate, but there are lots of cases
where it isn't. Expecting it to solve all of your problems will
only lead to more problems.

Sorry James, that's stupid.

Nobody's expected shared_ptr to solve all your problems.

It's very very very bad advice you're giving here.

[...]
Instead, what you probably need most is to discover that the standard
library's collection classes solve most of the problems you're
struggling with.
Some pointer usage will remain.

And most of it will be navigation. Where boost::shared_ptr
isn't appropriate.
For that, use smart pointers such as boost::shared_ptr so that
you don't have to struggle with deallocation and invalid
pointers and so on.

If the only problem is deallocation, the Boehm garbage collector
is a much simpler solution than boost::shared_ptr.

I know you're using that, but you're the only person I know of who does.

But neither
it nor boost::shared_ptr can protect you from all pointer
errors

You don't say.


[snip]
Just systematically replacing all raw pointers with
boost::shared_ptr, however, is almost guaranteed to get you into
trouble.

That would be stupid, yes.

Similarly stupid, just replacing all deallocation with the Boehm
collector would be almost guaranteed to get you into trouble.


Cheers,

- Alf
 
A

Alf P. Steinbach

* Alf P. Steinbach:
* James Kanze:
[...]
Use boost::shared_ptr instead of raw pointers.

That's bad advice, generally. There are cases where
boost::shared_ptr is appropriate, but there are lots of cases
where it isn't. Expecting it to solve all of your problems will
only lead to more problems.

Sorry James, that's stupid.

Nobody's expected shared_ptr to solve all your problems.

It's very very very bad advice you're giving here.

I forgot to mention, in addition to bad advice to the OP, you quoted me
out of context.

Were you awake when posting?

Cheers,

- Alf
 
J

James Kanze

* James Kanze:
[...]
Use boost::shared_ptr instead of raw pointers.
That's bad advice, generally. There are cases where
boost::shared_ptr is appropriate, but there are lots of cases
where it isn't. Expecting it to solve all of your problems will
only lead to more problems.
Sorry James, that's stupid.
Nobody's expected shared_ptr to solve all your problems.
It's very very very bad advice you're giving here.

Your statement, as it stands is bad advice. shared_ptr won't
solve his problem here. Judging from the name of the type
(Knoten), it will probably get him into deeper problems.
(Knoten suggests some sort of graph, which in turn suggests the
possibility of cycles.

In context, however: it's not clear from the context whether you
meant use shared_ptr instead of raw pointer as a general rule
(it's a bad one), or simply in this application (it's probably a
bad rule here as well, if Knoten means "node", as it usually
does in German), or simply in the array (and no where else). If
I misunderstood what you meant (it seemed clear when I read it
yesterday, but not so much today), I'm sorry.

Depending on the rest of the application (which we don't really
know), it might make sense to use shared_ptr in the array. But
I'll admit that I don't really follow the rest of his code that
well: "nodes", in all of the graph algorithms I know, are
manipulated by pointers, and are not copiable, but he later uses
pass by value. If by Knoten, he means something different than
the classical node in a graph, something with value semantics,
then the array should be of Knoten, and not any pointer type:
smart or raw. If Knoten doesn't have value semantics, on the
other hand, he should inhibit copy and assignment, and use
pointers everywhere. Probably raw pointers, at least most of
the time, but it's possible to arrange for all nodes to be in
some sort of "owning" vector, and use shared_ptr in it. (In
practice, of course, in most applications, shared_ptr has very
little use. Pointers to objects with value semantics are rare,
and entity objects generally manage their own lifetime, so the
use of shared_ptr is limited to a few special
cases---polymorphic agents and the like.)
[...]
Instead, what you probably need most is to discover that the standard
library's collection classes solve most of the problems you're
struggling with.
Some pointer usage will remain.
And most of it will be navigation. Where boost::shared_ptr
isn't appropriate.
If the only problem is deallocation, the Boehm garbage collector
is a much simpler solution than boost::shared_ptr.
I know you're using that, but you're the only person I know of
who does.

I use it because I'm in the business of producing reliable
software at the lowest cost possible. Any tool which reduces my
work load is good. But don't get me wrong. It's just one tool
of many, and it's not always applicable. (Getting legacy code
or third party libraries to work correctly with it isn't always
trivial.) And it's importance is considerably less than in
languages that don't have full support for value semantics; as I
said above, most objects in a C++ application either have value
semantics (and so aren't allocated dynamically to begin with),
or manage their own lifetime (in which case, garbage collection
is only a safety net). With or without it, however, I don't use
boost::shared_ptr very much.
[snip]
Just systematically replacing all raw pointers with
boost::shared_ptr, however, is almost guaranteed to get you into
trouble.
That would be stupid, yes.
Similarly stupid, just replacing all deallocation with the Boehm
collector would be almost guaranteed to get you into trouble.

All deallocation, no. But you still have to call some
destructors at a deterministic moment.

The real difference is that garbage collection separates memory
management from object lifetime. You still have to be concerned
with object lifetime. At the present state of the art, I don't
think any tool can relieve you of object lifetime
considerations; they're a design issue, and currently, I know of
no tool which can automatically handle design. What garbage
collection does is 1) ensures that the memory of a dead
(destructed) object doesn't get used for anything else as long
as there is a reachable pointer to it, so you can easily detect
the use of a dead object, and recognize it as such, and 2)
relieves you of the *implementation* details of objects for
which there is no significant activity at the end of lifetime
(typically, polymorphic agents and the like). boost::shared_ptr
is a very viable alternative in the second case; in the first,
it is somewhat more difficult to use because most of the
pointers involved are for navigation, with the result that there
are cycles which have to be broken.
 
J

James Kanze

The STL offers a good deal of dynamic data structures that
allow you to have data in dynamic memory without new()-ing
them yourself.

In business applications or process control, you'll have a lot
of individual entity objects with very arbitrary lifetimes:
they'll be created on reception of an external event, and
destructed on reception of a different event. That means
dynamic allocation. And there's nothing in the STL which will
help here, at least not directly. (The STL will usually be used
to hold pointers to the objects: at the very least, an std::set
or std::map, in order to find the object given an external
identifier. But the STL doesn't manage the objects, and no STL
container can really be considered "owner" of the objects.)
In teaching C++, I would first discuss the standard containers
before I dive into new() and delete(). (In fact, I would be
inclined to discuss new() and delete() in the context of
implementing containers.)

As I said, I'd almost certainly present std::vector and
std::string before pointers. In my mind, they're really "basic"
types in C++. However, dynamic data structures are a fact of
life, and more important and more fundamental than, say, the
ability to correctly design and write a class template, or even
(IMHO) inheritance.

It's about the simplest dynamic data structure I can think of.
I would rather expect the implementation of a
relative neophyte to contain subtle bugs like leaking memory
when copy-constructors throw. The cumbersome issue will be
that the neophyte will not even be able to see those issues.

There are several layers which have to be addressed. I'd
definitly start with lists of basic types.
Here, I strongly disagree. I would definitely discuss
try-throw-catch before diving into dynamic allocation issues.
The reasons are in the part of my previous post that you
snipped.

Given that new may throw, you may have a point there. But any
discussion of exceptions at that point would be very
superficial; at some point, IMHO, it's acceptable that a
student's program crash in the absense of sufficient resources.
The student can't learn everything at once.
You have a valid point here: The whole OO business needs
pointers to actually model the subclass thing (aka
is-a-relationship). If D is derived from B, it is not really
true that values of type D form a subset of values of type B.
The map from
Values(D) --> Values(B)
is a projection called slicing. On the other hand, the map
Values(D*) --> Values(B*)
is an honest inclusion: every D* is a B*.
Now the question is whether that observation implies that
pointers should come early or whether the right conclusion is
that OO should come late.

The problem here is that OO is really a design concept. There's
no point in teaching OO programming (in C++, or in any other
language) unless the programmer has mastered OO design. Of
course, replace OO with any other paradigm, and the same
statement still holds.

To tell the truth, I'm not sure how to approach this problem.
The general rule seems to be that a programming language (some
programming language) is taught right at the start. The result
is that you have to teach simple cases which don't require
design (because the students don't know design), and about all
you can really teach them is the basic mechanics of the
language: int and double, if and loops, and things like that.
And even that is limited---you normally only use a loop because
the design calls for it.

Among the courses I've seen (but I've not seen too many), the
only exception is the one at MIT. And there, the language is
Scheme---a language whose "mechanics" are so trivially simple
that you can spend time presenting design at the same time.

I think you could probably do this with a subset of C++ and a
specially designed library *for* *beginners* (which the STL is
not). I also think that doing this, you'd probably teach
pointers before you even got to classes---simple C-like struct's
are sufficient for a lot of things (provided you've provided the
necessary underlying tool kit).
I strongly sympathize with the later point of view. However,
teaching C++ very likely is not done just to master the
language, but to master specific tasks of programming (i.e.,
there are outside constraints and interests involved). I am
willing to acknowledge that given such constraints, OO might
even be the primary focus of the class, in which case pointers
will have to come very early.

The problem, I think, is that C++ is often used as the "first"
programming language, and that the attempt in that course is to
teach it more or less completely. I don't think that complete
C++, with the complete standard library, is appropriate for
this. (Nor is Java, the other frequent candidate.) I do think
that the power of C++ allows you to *create* a language within
C++ which is appropriate (unlike the case with Java).

If we're talking about a trade school, rather than a university,
where the role is to give them a course in the language, and
then get them employed using it, without any real theoretical
background, then you probably do have to present the OO aspects
early on, because if the student is to be employed working on
business software or industrial process control software, that's
what he'll need to know. Where as he probably won't (or
shouldn't) be called on to implement any basic generic
containers, which IMHO require a good deal of expertise. (But
I'm sceptical about this approach. Somehow, I don't think that
such a course will be able to produce programmers capable of
writing code which is thread safe and exception safe. And both
threads and exceptions are omnipresent in real life code in
these domains.)
On the other hand, I'd probably not teach everything about them
at that point.
[...]
Anyway, the most important knowledge about dynamic allocation
is the many ways of using the STL instead.
Not all of the ways. I'd certainly present std::vector and
std::string before pointers. I'd probably even present
iterators and algorithms, although I'm not sure. But I can't
quite seem teaching someone how to write and STL iterator before
he understands pointer basics.
Teaching how to write an STL conforming iterator is different
from teaching using the STL. I certainly would like the
student to see std::list<T>::iterator before T*.

I am a little worried about the basic uses getting the student
into bad habits that are hard to correct later.

It's something a prof has to watch out for. The bad habits
should result in lower grades, even if the student hasn't been
versed in all of the details as to why they are bad habits. (I
don't generally like this approach, but I don't see any other
real alternative.)
 
B

Bart van Ingen Schenau

Then often I have the problem that I have a method which should obtain a
non pointer variable, but in this case I only have a pointer to this
variable, and what then?

To turn a 'pointer to Something' into 'Something', you have to
dereference the pointer.
Let's see my actual example which leads to a "segemntation fault" or
doesn't even compile:
//This is weird. Here I want to iterate over every element of "knoten",
but....

for (int kBez = 0; kBez < groesse; kBez++) {
findKomponenten(knoten[kBez]); //LINE 178
}}

-------------------------------------------

...I get the following error message while compiling:

markus@gentoo ~/CPP-Programme/ $ g++ *.cpp -o Main `pkg-config gtkmm-2.4
--cflags --libs`
Adjazenzmatrix.cpp: In member function »void
Adjazenzmatrix::berechneEigenschaften()«:
Adjazenzmatrix.cpp:178: Fehler: ungültige Umwandlung von »Knoten*« in »int«
Adjazenzmatrix.cpp:178: Fehler: Argument 1 von »Knoten::Knoten(int)«
wird initialisiert

Which means something like:
Invalid conversion of "Knoten*" to "int.
Error: Argument 1 of Knoten::Knoten(int) will be initialized.

What does that mean?

Here is the method findKomponenten:

The compiler complays, because you try to pass a 'Knoten*' to a
function that expects a 'Knoten' parameter. The compiler tries to
convert for you, using the Knoten constructor, but fails.
To pass a 'Knoten' object, you would have to write line 178 as:
findKomponenten(*knoten[kBez]); //LINE 178
Note that this will cause a *copy* of the relevant array element to be
passed.

As you can see, I use a self programmed dynamically list in this class.
Now it's getting complicated for me. Later in this class, I initialize
new ListT-elements which are also "Knoten". I want to access those
elements from Adjazenzmatrix so I have sometimes already pointer with
the deep of two and then I'm not sure anymore how to handle it.
I don't know if I should return a pointer or not or as I already said,
the return values doesn't "fit" to the class which invokes the methods
of the instances because the method returns a non pointer value but in
the invoking class I have a pointer.

C++ is not a language that easily lets you fiddle about. To get a
working, moderately complex system, you need to think about the design
before you write the first line of code. This includes thinking about
how you are going to pass parameters/return values about.
And remember that C++ is very eager to make copies of things. If you
don't want a copy, you will have to explicitly use a reference or
pointer (and think about if the object you are passing will live long
enough).
I alwasy fight with such problems, so I need to get deeper into the
knowledge of handling with pointer.

Markus

Bart v Ingen Schenau
 
A

Alf P. Steinbach

* James Kanze:
* James Kanze:
[...]
Use boost::shared_ptr instead of raw pointers.
That's bad advice, generally. There are cases where
boost::shared_ptr is appropriate, but there are lots of cases
where it isn't. Expecting it to solve all of your problems will
only lead to more problems.
Sorry James, that's stupid.
Nobody's expected shared_ptr to solve all your problems.
It's very very very bad advice you're giving here.

Your statement, as it stands is bad advice. shared_ptr won't
solve his problem here. Judging from the name of the type
(Knoten), it will probably get him into deeper problems.
(Knoten suggests some sort of graph, which in turn suggests the
possibility of cycles.

I'm sorry, but that adds further invalid reasoning on top of what you
wrote earlier.

You're arguing that the OP should avoid smart pointers in order to be
able to deal more easily with cycles.

It almost sounds like your brain's been taken over by a certain other
anti-smart-pointer poster in this group.

Don't you see how fallacious your statement is?

Or are you simply dissembling?


Cheers,

- Alf
 
J

James Kanze

* James Kanze:
* James Kanze:
[...]
Use boost::shared_ptr instead of raw pointers.
That's bad advice, generally. There are cases where
boost::shared_ptr is appropriate, but there are lots of cases
where it isn't. Expecting it to solve all of your problems will
only lead to more problems.
Sorry James, that's stupid.
Nobody's expected shared_ptr to solve all your problems.
It's very very very bad advice you're giving here.
Your statement, as it stands is bad advice. shared_ptr won't
solve his problem here. Judging from the name of the type
(Knoten), it will probably get him into deeper problems.
(Knoten suggests some sort of graph, which in turn suggests the
possibility of cycles.
I'm sorry, but that adds further invalid reasoning on top of what you
wrote earlier.

How? boost::shared_ptr doesn't handle cycles.
You're arguing that the OP should avoid smart pointers in order to be
able to deal more easily with cycles.

No. I'm saying that boost::smart_ptr won't work when cycles are
present.

If, as the name suggests, he's dealing with a graph of some
sort, then raw pointers are probably the easiest solution. With
garbage collection, if possible, because this is the sort or
case where garbage collection excells. Otherwise, you need some
sort of strategy to decide the lifetime of the objects;
reference counting (as used by boost::shared_ptr) *doesn't*
work.
It almost sounds like your brain's been taken over by a certain other
anti-smart-pointer poster in this group.

My brain has been taken over by common sense and actual
experience.
Don't you see how fallacious your statement is?

Don't you see how fallacious your statement is? In this case,
boost::shared_ptr is NOT a good solution. In general, there are
a few special cases where it is a solution, but they don't
predominate.

In this particular case, the first step to finding a solution is
to decide whether Knoten has value semantics or not. If it has
value semantics, *no* pointer is the correct solution. If it
doesn't, and as its name suggests, it is used to implement some
sort of graph, then in the absense of garbage collection, memory
management must be implemented at the graph level, not at the
pointer level. Suggestions to use boost::shared_ptr simply show
a lack of understanding of the problem.
 
A

Alf P. Steinbach

* James Kanze:
* James Kanze:
* James Kanze:
[...]
Use boost::shared_ptr instead of raw pointers.
That's bad advice, generally. There are cases where
boost::shared_ptr is appropriate, but there are lots of cases
where it isn't. Expecting it to solve all of your problems will
only lead to more problems.
Sorry James, that's stupid.
Nobody's expected shared_ptr to solve all your problems.
It's very very very bad advice you're giving here.
Your statement, as it stands is bad advice. shared_ptr won't
solve his problem here. Judging from the name of the type
(Knoten), it will probably get him into deeper problems.
(Knoten suggests some sort of graph, which in turn suggests the
possibility of cycles.
I'm sorry, but that adds further invalid reasoning on top of what you
wrote earlier.

How?


That's the entirely wrong issue to focus on. Anyway, you already got an
answer to that, quoted below.

> boost::shared_ptr doesn't handle cycles.

In most of the few cases where that is an issue, a weak_ptr is an
appropriate solution to break the cyclic dependency.

Only with arbitrary dynamic sharing of substructure is a more powerful
strategy generally indicated.

You show a lack of understanding of both the technical issues and the
pedagogical ones.


No. I'm saying that boost::smart_ptr won't work when cycles are
present.

I'm sorry, that's incorrect.

It's /possible/ to write incorrect code, and cycles are indeed one case
where it's "easier" to write incorrect code than in general. Writing
incorrect code is possible regardless of use of smart pointers or not,
but it's far more likely with a novice not using smart pointers. From
the relative likelyhood of writing incorrect code in one possible case,
regardless of smart pointers or not, you're drawing the invalid
conclusion that that means it's impossible to write correct code when
using smart pointers.

Don't you see how fallacious that is?

Or perhaps you don't.

Well then, just eat the fact that it's possible to write correct code
using smart pointers, also for graphs with cycles.

Also, think about this: the OP has not stated that cycles are a problem,
or given code with cycles, or stated or indicated that the code
represents graph edges using pointers, or even stated or indicated that
the code in question deals with a graph structure, or stated or
indicated that the code given is the primary problem (in fact, the
problem was described as being of a more general nature).

It's an arbitrary possible problem you have focused on, where you could
just as well have focused on the possible problem of thread safety, or
whatever, and the solution in neither case is generally not to avoid
smart pointers.

If, as the name suggests, he's dealing with a graph of some
sort, then raw pointers are probably the easiest solution. With
garbage collection, if possible, because this is the sort or
case where garbage collection excells. Otherwise, you need some
sort of strategy to decide the lifetime of the objects;
reference counting (as used by boost::shared_ptr) *doesn't*
work.

Bull. And that doesn't mean that the opposite is always true.


Cheers,

- Alf
 
J

James Kanze

* James Kanze:
* James Kanze:
* James Kanze:
[...]
Use boost::shared_ptr instead of raw pointers.
That's bad advice, generally. There are cases where
boost::shared_ptr is appropriate, but there are lots of cases
where it isn't. Expecting it to solve all of your problems will
only lead to more problems.
Sorry James, that's stupid.
Nobody's expected shared_ptr to solve all your problems.
It's very very very bad advice you're giving here.
Your statement, as it stands is bad advice. shared_ptr won't
solve his problem here. Judging from the name of the type
(Knoten), it will probably get him into deeper problems.
(Knoten suggests some sort of graph, which in turn suggests the
possibility of cycles.
I'm sorry, but that adds further invalid reasoning on top of what you
wrote earlier.

That's the entirely wrong issue to focus on. Anyway, you already got an
answer to that, quoted below.
boost::shared_ptr doesn't handle cycles.
In most of the few cases where that is an issue, a weak_ptr is
an appropriate solution to break the cyclic dependency.

When pointers are used for navigation (presumably the case if we
are dealing with "nodes"---the English translation of Knoten),
we almost always have cycles. Often very complex ones. In
practice, trying to figure out which pointers should be
weak_ptr, and which should be shared_ptr, is more work, and more
error prone, than just using raw pointers, and managing memory
at a higher level.
Only with arbitrary dynamic sharing of substructure is a more
powerful strategy generally indicated.
You show a lack of understanding of both the technical issues
and the pedagogical ones.

All I'm showing is that I have actual experience with the
problem. I've tried boost::shared_ptr, and found that in such
cases, it introduced more problems than it solved.
I'm sorry, that's incorrect.

It's provable correct. (Obviously, I mistyped, and meant
boost::shared_ptr, since that was the only thing mentioned up
until this point.)
It's /possible/ to write incorrect code,

It's even very easy, with boost::shared_ptr.
and cycles are indeed one case where it's "easier" to write
incorrect code than in general. Writing incorrect code is
possible regardless of use of smart pointers or not, but it's
far more likely with a novice not using smart pointers.

And that is simply wrong. Smart pointers only work in specific
cases. Those that they were designed for. A novice needs to
understand pointers and memory management in order to correctly
select which smart pointer is appropriate, if any. (Most of the
time, at least in the domains I work in, pointers are used for
navigation, and raw pointers are generally more appropriate than
smart pointers.)
From
the relative likelyhood of writing incorrect code in one
possible case, regardless of smart pointers or not, you're
drawing the invalid conclusion that that means it's impossible
to write correct code when using smart pointers.

No I'm not. I quite explicitly said that smart pointers have
their use. They just don't happen to be appropriate in this
case.
Don't you see how fallacious that is?

All I see is that your creating strawmen to argue against, and
mis-presenting what I said.
Or perhaps you don't.
Well then, just eat the fact that it's possible to write
correct code using smart pointers, also for graphs with
cycles.

But not with boost::shared_ptr. You need several different
types of smart pointers, and it's actually more work and more
error prone than using raw pointers, and managing the memory at
a higher level.
Also, think about this: the OP has not stated that cycles are
a problem, or given code with cycles, or stated or indicated
that the code represents graph edges using pointers, or even
stated or indicated that the code in question deals with a
graph structure, or stated or indicated that the code given is
the primary problem (in fact, the problem was described as
being of a more general nature).

All the OP has stated is that he is having problems
understanding pointers. He also posted code which seemed to mix
value semantics with reference semantics, which suggests that he
has a much more fundamental problem in understanding.
Introducing different types of smart pointers at this point can
only add to the confusion.
 
M

Markus Pitha

Hello again,

thanks to everyone for your answers.
I rewrote my complete program to use std::vector instead of my ListT
class and std::vector seemed to make the job. I get no errors anymore.

Markus
 

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

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top