Is this good style of C++?

I

Ioannis Vranos

Dave said:
Almost! A reference-counted smart pointer, like Boost shared_ptr, does
not solve the object ownership problem. It just changes its form from
manual new/delete to something like a reference-counted GC. This
eliminates dangling pointers, but it does not eliminate all memory
leaks. If you store a smart pointer away somewhere and forget about it,
you will leak memory.

I am mostly aware of this from Java, where I have seen a lot of code
that leaked memory in this manner. In some ways, dangling pointers are
easier to deal with than GC or reference counting, because the app will
(usually...) crash on the use of the dangling pointer. With "safe"
things like shared_ptr, the app will keep running, with no warning that
some object you thought you released the last reference to is still
referenced.


What about a vector with one element for single objects?
 
R

red floyd

Ioannis said:
What about a vector with one element for single objects?
For a single dynamically allocated object, why not use an object instead
of a pointer, of if you can't (say from a Factory or whatever), why not
use auto_ptr?

Yeah, I know about all the issues with auto_ptr, but if you're using a
single object that's going to be deleted when it goes out of scope, why
not pick up the exception safety that auto_ptr gives?
 
D

Dave O'Hearn

Ioannis said:
Dave said:
Almost! A reference-counted smart pointer, like Boost shared_ptr,
does not solve the object ownership problem. It just changes its
form from manual new/delete to something like a reference-counted
GC. This eliminates dangling pointers, but it does not eliminate
all memory leaks. If you store a smart pointer away somewhere and
forget about it, you will leak memory.
[...]

What about a vector with one element for single objects?

I can't think of any uses for that that aren't better-covered by
something else. Vector is good for managing an array, so you don't have
to remember to free the array or manually keep track of its size. For
individual objects, I can think of,

1. Just keep it by value on the stack
2. auto_ptr
3. a reference counted smart pointer, like Boost shared_ptr
4. some kind of "weak reference" like Boost weak_ptr

There is no general solution to the problem I complained about. Weak
references help sometimes. Smart pointers reduce common errors when
doing simple things, which is the majority of code, but the worst kind
of errors are still possible, only they take on a different form.
 
I

Ioannis Vranos

red said:
For a single dynamically allocated object, why not use an object instead
of a pointer, of if you can't (say from a Factory or whatever), why not
use auto_ptr?


I was talking about a third party class (e.g. some GUI Form class that
is required to be created in the heap.


Also I meant "in addition to auto_ptr possibility".
 
I

Ioannis Vranos

Dave said:
I can't think of any uses for that that aren't better-covered by
something else. Vector is good for managing an array, so you don't have
to remember to free the array or manually keep track of its size. For
individual objects, I can think of,

1. Just keep it by value on the stack
2. auto_ptr
3. a reference counted smart pointer, like Boost shared_ptr
4. some kind of "weak reference" like Boost weak_ptr

There is no general solution to the problem I complained about. Weak
references help sometimes. Smart pointers reduce common errors when
doing simple things, which is the majority of code, but the worst kind
of errors are still possible, only they take on a different form.


I am not familiar with the Boost library, however I think what would be
needed is a pointer type without "strong copy" semantics that auto_ptr
is. That is, it would allow the copying of the pointer value, while at
the same time would delete the object at the end of its scope or when an
exception is thrown.


Is there any such type in Boost?
 
P

Peter Koch Larsen

Dave O'Hearn said:
Almost! A reference-counted smart pointer, like Boost shared_ptr, does
not solve the object ownership problem. It just changes its form from
manual new/delete to something like a reference-counted GC. This
eliminates dangling pointers, but it does not eliminate all memory
leaks.

I am not sure I understand what you mean here. I believe the smart pointer
does protect my resource, whether it is memory, an open file, a socket
handle or something else.
If you store a smart pointer away somewhere and forget about it,
you will leak memory.
I still do not understand. What do you mean by "store away and forget it"?
If it is still accessible from the program, you can not deallocate it.
I am mostly aware of this from Java, where I have seen a lot of code
that leaked memory in this manner.

This is not a specifically a problem with memory. It relates to all
ressources used by a program.
In some ways, dangling pointers are
easier to deal with than GC or reference counting, because the app will
(usually...) crash on the use of the dangling pointer.
A dangling pointer? Using a smart pointer, it should never be dangling. It
could be 0, but that is expected.
With "safe"
things like shared_ptr, the app will keep running, with no warning that
some object you thought you released the last reference to is still
referenced.

With a smart pointer, you do not need to care.

/Peter
 
M

Morgan Cheng

Ioannis said:
I want to mention here that using RAII in your applications is fairly easy.


The most obvious way is to use a vector for your objects (or some other
standard library container if it is more suitable), instead of an array
in the free store.


And you have no space/time cost doing this.
Are you sure? I think that std::vector costs more time and space.
 
D

Dave O'Hearn

Peter said:
I am not sure I understand what you mean here. I believe the smart
pointer does protect my resource, whether it is memory, an open
file, a socket handle or something else.


I still do not understand. What do you mean by "store away and
forget it"? If it is still accessible from the program, you can
not deallocate it.

I mean the kind of bug that, with a raw pointer, is a dangling pointer.
You stored the pointer somewhere, in an Observer, or an event registry,
or something else, and forgot it was there. For example,

1. User A connects to my application. I new up a User object for him
and put it in a shared_ptr, and store it in my connected_users
collection.

2. User A subscribes to an event. The shared_ptr is now stored in the
event_registry collection.

3. User A logs out. I drop the reference from connected_users.

4. Oops. I forgot to drop the reference from event_registry. I leak
memory.

5. User A logs in again. Repeat from Step 1. I also now have multiple
copies of the same User in the system, and some may have stale data.

Without shared_ptr, it is a dangling pointer in the event_registry.
With shared_ptr, it is a memory leak. If "memory leak" is not exactly
the correct term, I have also heard them called "loitering objects". In
any case, it is a bug, and shared_ptr won't fix it. Except in
temporaries and simple aggregates, we still have to manage an object's
lifecycle properly.
This is not a specifically a problem with memory. It relates to all
ressources used by a program.

All resources that live long-term on the heap. Usually that is memory,
but someone could always put a file or something on the heap if they
had a reason to.
A dangling pointer? Using a smart pointer, it should never be
dangling. It could be 0, but that is expected.


With a smart pointer, you do not need to care.

If you want a resource freed and it doesn't free, it's a bug. It might
be your fault, for wanting it freed when the app still needs it, or it
might be the app's fault for holding onto it when it shouldn't. But
somewhere, there is a bug.
 
D

Dave O'Hearn

Ioannis said:
I am not familiar with the Boost library, however I think what
would be needed is a pointer type without "strong copy" semantics
that auto_ptr is. That is, it would allow the copying of the
pointer value, while at the same time would delete the object at
the end of its scope or when an exception is thrown.

Is there any such type in Boost?

If deleting at the end of the scope is all you need, then auto_ptr is
probably enough. Just create an auto_ptr, or const auto_ptr so it can't
be copied, at the top of the scope. You can then use get() to get the
raw pointer, and copy it around as much as you want. It will be deleted
when the auto_ptr goes out of scope.

Boost shared_ptr uses reference counting, so you can make as many
copies of it as you want, and it won't delete the object until the last
copy goes out of scope. It is good whenever you want to implement
reference counting, so you don't have to implement it yourself. It is
also useful because it lets you create "weak pointers" related to the
shared_ptr, but which automatically 0 when the object is freed.

http://www.boost.org/libs/smart_ptr/shared_ptr.htm

shared_ptr will probably be in the next revision of standard C++ so
it's good to get familiar with it.
 
P

Peter Koch Larsen

Dave O'Hearn said:
I mean the kind of bug that, with a raw pointer, is a dangling pointer.
You stored the pointer somewhere, in an Observer, or an event registry,
or something else, and forgot it was there. For example,

1. User A connects to my application. I new up a User object for him
and put it in a shared_ptr, and store it in my connected_users
collection.

2. User A subscribes to an event. The shared_ptr is now stored in the
event_registry collection.

3. User A logs out. I drop the reference from connected_users.

4. Oops. I forgot to drop the reference from event_registry. I leak
memory.

5. User A logs in again. Repeat from Step 1. I also now have multiple
copies of the same User in the system, and some may have stale data.

Without shared_ptr, it is a dangling pointer in the event_registry.
With shared_ptr, it is a memory leak. If "memory leak" is not exactly
the correct term, I have also heard them called "loitering objects". In
any case, it is a bug, and shared_ptr won't fix it. Except in
temporaries and simple aggregates, we still have to manage an object's
lifecycle properly.


All resources that live long-term on the heap. Usually that is memory,
but someone could always put a file or something on the heap if they
had a reason to.


If you want a resource freed and it doesn't free, it's a bug. It might
be your fault, for wanting it freed when the app still needs it, or it
might be the app's fault for holding onto it when it shouldn't. But
somewhere, there is a bug.
I believe the code you described is buggy. In your case, the Observer should
not have a shared_ptr to the user (perhaps a weak pointer). Also, observers
should automatically be notified if something the observe disappears.

/Peter
 

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
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top