468,720 Members | 1,803 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,720 developers. It's quick & easy.

Is this good style of C++?

Recently I happens to read some sourcecode which has different style
from my previous experience.

In this style, all functions return a RETURN_TYPE_T which is defined as
typedef unsigned int RETURN_TYPE_T;
and the return value can only be enum value
enum
{
SUCCESS = 0,
FAILURE = 1,
ABORT = 2
};
If a function should return a object, the API is not like
Foo getFoo();
or
Foo* getFoo();
Instead, it is declared as
RETURN_TYPE_T getFoo(Foo* foo);
The caller has to new a Foo or get pointer to Foo object through other
way first, and then call this method with the pointer as parameter.

The function fill valuable info into the Foo object pointed by the
paramter. The result of invocation is judged by inspecting the returned
RETURN_TYPE_T value.

This style of coding seems strange to me, but I am told that it is a
good style, because it applys the rule "Who creates it, who releases
it". As a result, this style are supposed to reduce risk of memory leak.

I am still not quite convinced. Anybody with long time C++ exprirence
can give some comments?
Thanks & Regards

Jul 22 '05 #1
29 1673
Cheng Mo wrote:
Recently I happens to read some sourcecode which has different style
from my previous experience.

In this style, all functions return a RETURN_TYPE_T which is defined as
typedef unsigned int RETURN_TYPE_T;
and the return value can only be enum value
enum
{
SUCCESS = 0,
FAILURE = 1,
ABORT = 2
};
If a function should return a object, the API is not like
Foo getFoo();
or
Foo* getFoo();
Instead, it is declared as
RETURN_TYPE_T getFoo(Foo* foo);
The caller has to new a Foo or get pointer to Foo object through other
way first, and then call this method with the pointer as parameter.

The function fill valuable info into the Foo object pointed by the
paramter. The result of invocation is judged by inspecting the returned
RETURN_TYPE_T value.

This style of coding seems strange to me, but I am told that it is a
good style, because it applys the rule "Who creates it, who releases
it". As a result, this style are supposed to reduce risk of memory leak.

I am still not quite convinced. Anybody with long time C++ exprirence
can give some comments?



If such a style is used in an application for a particular reason (that
is, it is not a style), then it is OK.
Otherwise as a *general style* of programming for C++ it looks primitive
and ancient.
If you want to handle errors you had better use exceptions, and not
return error code checks that this style implies.
If you want to create bullet proof code without memory leaks or *any
other resource* leaks, use "Resource Acquisition is Initialisation" (RAII):
http://groups.google.com/groups?q=%2...ntua.gr&rnum=1


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #2
All in all its horrible.

"Cheng Mo" <mo******@nospam.nospam> skrev i en meddelelse
news:co**********@avnika.corp.mot.com...
Recently I happens to read some sourcecode which has different style from
my previous experience.

In this style, all functions return a RETURN_TYPE_T which is defined as
typedef unsigned int RETURN_TYPE_T;
and the return value can only be enum value
enum
{
SUCCESS = 0,
FAILURE = 1,
ABORT = 2
}; Do not use UPPERCASE_ONLY for values. These names should be reserved for
macroes only. If a function should return a object, the API is not like
Foo getFoo();
or
Foo* getFoo();
Instead, it is declared as
RETURN_TYPE_T getFoo(Foo* foo);
The caller has to new a Foo or get pointer to Foo object through other way
first, and then call this method with the pointer as parameter. Also horrible. The first signature should be preferred unless the call could
fail in a normal case in which case a smart pointer (see boost) would be
appropriate.
The function fill valuable info into the Foo object pointed by the
paramter. The result of invocation is judged by inspecting the returned
RETURN_TYPE_T value. In general, using exceptions is far more reliable. There's no forgetting of
checking the return-type, and you would not have to obfuscate your code with
all that checking.
This style of coding seems strange to me, but I am told that it is a good
style, because it applys the rule "Who creates it, who releases it". As a
result, this style are supposed to reduce risk of memory leak. This is good advice, but not so relevant for C++. Use RAII instead.
I am still not quite convinced. Anybody with long time C++ exprirence can
give some comments?
Thanks & Regards


Kind regards
Peter
Jul 22 '05 #3
Peter Koch Larsen wrote:
Do not use UPPERCASE_ONLY for values. These names should be reserved for
macroes only.

Actually one convention is to name all constants with uppercase, be them
macros, const objects, or members of an enumeration.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #4
>> If a function should return a object, the API is not like
Foo getFoo();
or
Foo* getFoo();
Instead, it is declared as
RETURN_TYPE_T getFoo(Foo* foo);
The caller has to new a Foo or get pointer to Foo object through other
way first, and then call this method with the pointer as parameter.

The function fill valuable info into the Foo object pointed by the
paramter. The result of invocation is judged by inspecting the returned
RETURN_TYPE_T value.

This style of coding seems strange to me, but I am told that it is a
good style, because it applys the rule "Who creates it, who releases
it". As a result, this style are supposed to reduce risk of memory leak.
If you want to handle errors you had better use exceptions, and not
return error code checks that this style implies.


Unless errors are frequent and expected, in which case exceptions are not
such a good choice. Throwing an exception typically has big overheads, so
unless given error is *exceptional*, it should be handled w/o throwing an
exception. Network code comes to mind, if transmission errors, timeouts
etc. are frequent.

Cheers, Kuba Ober
Jul 22 '05 #5
Kuba Ober wrote:
Unless errors are frequent and expected, in which case exceptions are not
such a good choice. Throwing an exception typically has big overheads, so
unless given error is *exceptional*, it should be handled w/o throwing an
exception. Network code comes to mind, if transmission errors, timeouts
etc. are frequent.

Well, my experience is in .NET, where every error is signified as an
exception and not as a return value, and so far I had no problems with
it. Also all the C++ standard library with the exception of the C
subset, uses exceptions to signify run-time errors.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #6

"Kuba Ober" <ku**@mareimbrium.org> wrote in message
news:co**********@charm.magnus.acs.ohio-state.edu...
If you want to handle errors you had better use exceptions, and not
return error code checks that this style implies.


Unless errors are frequent and expected, in which case exceptions are not
such a good choice.


Unexpected behavior is pretty much the definition of an exception.
Jul 22 '05 #7
Ioannis Vranos <iv*@remove.this.grad.com> wrote in
news:1102010767.803954@athnrd02:
Kuba Ober wrote:
Unless errors are frequent and expected, in which case exceptions are
not such a good choice. Throwing an exception typically has big
overheads, so unless given error is *exceptional*, it should be
handled w/o throwing an exception. Network code comes to mind, if
transmission errors, timeouts etc. are frequent.

Well, my experience is in .NET, where every error is signified as an
exception and not as a return value, and so far I had no problems with
it. Also all the C++ standard library with the exception of the C
subset, uses exceptions to signify run-time errors.


I don't agree with that assessment. End-of-file on a stream, for example,
is _not_ an exception, neither is dynamic_casting a pointer to an unrelated
type. Offhand I can only think of a couple of places where an exception is
thrown from the Standard library, and that's because either it really is an
exceptional case (like running out of memory), or there is no other way to
indicate an error (like dynamic_casting a reference to an unrelated type,
or using .at() on a vector past the end of the vector).
Jul 22 '05 #8
Andre Kostur wrote:
I don't agree with that assessment. End-of-file on a stream, for example,
is _not_ an exception, neither is dynamic_casting a pointer to an unrelated
type.

These are not errors. End-of-file is just the end of a file and
dynamic_cast is actually a run-time test.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #9
Ioannis Vranos <iv*@remove.this.grad.com> wrote in
news:1102022154.76165@athnrd02:
Andre Kostur wrote:
I don't agree with that assessment. End-of-file on a stream, for
example, is _not_ an exception, neither is dynamic_casting a pointer
to an unrelated type.


These are not errors. End-of-file is just the end of a file and
dynamic_cast is actually a run-time test.


Then I don't understand exactly what you would call an "error" then. IMHO:
If I try to read some data from a stream, and I don't get the data I was
expecting, then I'd call that an error. If I try to dynamic_cast a pointer
to an unrelated type, the runtime will return me a NULL to signify that
error. If I try to dynamic_cast a reference to an unrelated type, the
runtime will throw an exception to signify that error.
Jul 22 '05 #10
Andre Kostur wrote:
These are not errors. End-of-file is just the end of a file and
dynamic_cast is actually a run-time test.

Then I don't understand exactly what you would call an "error" then.

In general, an unexpected situation.
IMHO:
If I try to read some data from a stream, and I don't get the data I was
expecting, then I'd call that an error.
Well, when you read the data from a stream, checking if its end has been
reached is a rational thing to do.

If I try to dynamic_cast a pointer
to an unrelated type, the runtime will return me a NULL

Actually a 0.

to signify that
error. If I try to dynamic_cast a reference to an unrelated type, the
runtime will throw an exception to signify that error.


Dynamic cast is aimed for "Run-time Type Identification" (RTTI), so this
is not an error. Consider this:

void someFunc(Base *p)
{
Derived1 *dp1= dynamic_cast<Derived1 *>(p);

if(dp1!= 0)
{
// ...

return;
}

Derived2 *dp2= dynamic_cast<Derived2 *>(p);

if(dp2!= 0)
{
// ...

return;
}

// ...
}


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #11
Ioannis Vranos wrote:
Andre Kostur wrote:
These are not errors. End-of-file is just the end of a file and
dynamic_cast is actually a run-time test.


Then I don't understand exactly what you would call an "error" then.


In general, an unexpected situation.


The problem with using the term "error"
is that it requires a [subjective] value judgment.

C++ programmers prefer the more neutral term *exception*
to reference *rare* and *unpredictable* events
that are *expected* but cannot be *prevented*.

Programming errors (bugs), on the other hand,
are unexpected until they are discovered
at which point they are completely predicable
and can be prevented by fixing the bug.

Exceptions should be handled at the point
where they are detected if possible.
If the exception cannot be handled where it is detected
all of the information needed to handle the exception
in the calling program should be encapsulated in an exception object
and the exception should be returned or thrown.

Functions like

Foo getFoo(void);

which return a value may be used in expressions
so they must throw an exception
if it cannot be completely within getFoo(void)
and that exception *must* be caught and handled
by the calling program.
Jul 22 '05 #12
Peter Koch Larsen wrote:
This style of coding seems strange to me, but I am told that it is a good
style, because it applys the rule "Who creates it, who releases it". As a
result, this style are supposed to reduce risk of memory leak.


This is good advice, but not so relevant for C++. Use RAII instead.


I read some doc got from google. It seems that RAII just a axiom that
requires that acquired resource should be released. However, this is not
easy to follow in C++ because if object is new-d in one part of code
and another part release it as design. It is quite possible that new-d
object is not released for human negligence.

"Who creates int, who releases it" emphasize that the part of code "new"
the object should take the responsibility to "delete" the object
explictly. With this discipline, it is not easy to cause memory leak.
IMO, this rule is more strict than RAII.
Jul 22 '05 #13
Morgan Cheng wrote:

Peter Koch Larsen wrote:
This style of coding seems strange to me, but I am told that it is a good
style, because it applys the rule "Who creates it, who releases it". As a
result, this style are supposed to reduce risk of memory leak.
This is good advice, but not so relevant for C++. Use RAII instead.


I read some doc got from google. It seems that RAII just a axiom that
requires that acquired resource should be released. However, this is not
easy to follow in C++ because if object is new-d in one part of code
and another part release it as design. It is quite possible that new-d
object is not released for human negligence.


RAII as it is used in C++ is actually a simple thing to do in C++.
All you need to do, is to encapsulate the resource into a class of its
own. The constructor manages the allocation, the destructor releases
the resource. (+copy constructor, + assignment operator).
Users of that resource never deal with the dynamic allocation aspect. All
they ever use is an object of that class, and the object does all the
dynamic work.

Just think of std::string in contrast to plain-vanilla C-style strings.
std::string manages the C-style string under the hood. Users of std::string
never have to deal with that.

"Who creates int, who releases it" emphasize that the part of code "new"
the object should take the responsibility to "delete" the object
explictly. With this discipline, it is not easy to cause memory leak.
IMO, this rule is more strict than RAII.


RAII (as it is understood in C++) is exactly that principle encapsulated
in a class, with constructors and destructors doing all the work.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #14
Morgan Cheng wrote:
I read some doc got from google. It seems that RAII just a axiom that
requires that acquired resource should be released. However, this is not
easy to follow in C++ because if object is new-d in one part of code
and another part release it as design. It is quite possible that new-d
object is not released for human negligence.

"Who creates int, who releases it" emphasize that the part of code "new"
the object should take the responsibility to "delete" the object
explictly. With this discipline, it is not easy to cause memory leak.
IMO, this rule is more strict than RAII.

Check this:
http://groups.google.com/groups?q=%2...ntua.gr&rnum=1

When you manage your memory manually, there can always be a memory leak,
when an exception is thrown for example.
So you had better use RAII (= host objects in the stack) for memory and
other resources.
What does this mean? When you need to create a particular object in the
free store, you may use a smart pointer like auto_ptr, or create your
own host class for a particular resource.
For many objects use a standard library container like vector, list, etc.
So consider these examples:
// 10 Buttons created in the free store.
// Buttons are destroyed at the end of the scope, or when an exception
// is thrown.
vector<Buttons> options(10);
// p will automatically delete the pointed object
// at the end of its scope, or when an exception is thrown.
auto_ptr<Form> p(new Form);
// Use p as a Form *
p->Show();

// There are other resources apart from memory that can leak
class IPConnection
{
// ...

public:
IPConnection()
{
// Opens the connection ...
// Perhaps also new something;
}

~IPConnection()
{
// Closes the connection...
// delete something;
}
};
// Destructor is called at the end of the scope and when an
// exception is thrown, cleaning the resources.
IPConnection ip1;


All the above are RAII: Destructor is called at the end of the scope and
when an exception is thrown, cleaning the resources.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #15
Ioannis Vranos wrote:
Morgan Cheng wrote:
I read some doc got from google. It seems that RAII just a axiom that
requires that acquired resource should be released. However, this is
not easy to follow in C++ because if object is new-d in one part of
code and another part release it as design. It is quite possible that
new-d object is not released for human negligence.

"Who creates int, who releases it" emphasize that the part of code
"new" the object should take the responsibility to "delete" the object
explictly. With this discipline, it is not easy to cause memory leak.
IMO, this rule is more strict than RAII.
Check this:
http://groups.google.com/groups?q=%2...ntua.gr&rnum=1

When you manage your memory manually, there can always be a memory leak,
when an exception is thrown for example.


If I implements RAII strictly, do you mean that memory leak can be
avoided totally? even exception is possibly to be thrown?


So you had better use RAII (= host objects in the stack) for memory and
other resources.
What does this mean? When you need to create a particular object in the
free store, you may use a smart pointer like auto_ptr, or create your
own host class for a particular resource.
For many objects use a standard library container like vector, list, etc.
So consider these examples:
// 10 Buttons created in the free store.
// Buttons are destroyed at the end of the scope, or when an exception
// is thrown.
vector<Buttons> options(10);
// p will automatically delete the pointed object
// at the end of its scope, or when an exception is thrown.
auto_ptr<Form> p(new Form);
// Use p as a Form *
p->Show();

// There are other resources apart from memory that can leak
class IPConnection
{
// ...

public:
IPConnection()
{
// Opens the connection ...
// Perhaps also new something;
}

~IPConnection()
{
// Closes the connection...
// delete something;
}
};
// Destructor is called at the end of the scope and when an
// exception is thrown, cleaning the resources.
IPConnection ip1;


All the above are RAII: Destructor is called at the end of the scope and
when an exception is thrown, cleaning the resources.


So, RAII is based on the fact that: At the end of a scope, through
normal running or exception thrown, objects in the scope will be
destructed. If resource is allocated explictly, objects pointed by
pointer will not be released by releasing the pointer. So, we wrap
dynamic resource allocation with a local object.
Am my understanding right?

Jul 22 '05 #16
Morgan Cheng wrote:
If I implements RAII strictly, do you mean that memory leak can be
avoided totally? even exception is possibly to be thrown?

Yes, along with other resource types leaks (IP connections, file
operations etc).
All C++ standard library types support RAII (except of the C subset
types of course).
So, RAII is based on the fact that: At the end of a scope, through
normal running or exception thrown, objects in the scope will be
destructed.

Exactly.
If resource is allocated explictly, objects pointed by
pointer will not be released by releasing the pointer. So, we wrap
dynamic resource allocation with a local object.
Am my understanding right?

Yes.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #17
Ioannis Vranos wrote:

Morgan Cheng wrote:
If I implements RAII strictly, do you mean that memory leak can be
avoided totally? even exception is possibly to be thrown?


Yes, along with other resource types leaks (IP connections, file
operations etc).
All C++ standard library types support RAII (except of the C subset
types of course).
So, RAII is based on the fact that: At the end of a scope, through
normal running or exception thrown, objects in the scope will be
destructed.


Exactly.
If resource is allocated explictly, objects pointed by pointer will
not be released by releasing the pointer. So, we wrap dynamic resource
allocation with a local object.
Am my understanding right?


Yes.

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.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #18

"Morgan Cheng" <mo************@gmail.com> skrev i en meddelelse
news:41**************@gmail.com...
Ioannis Vranos wrote:
Morgan Cheng wrote:

[snip] If I implements RAII strictly, do you mean that memory leak can be avoided
totally? even exception is possibly to be thrown? Yes. [snip] So, RAII is based on the fact that: At the end of a scope, through normal
running or exception thrown, objects in the scope will be destructed. If
resource is allocated explictly, objects pointed by pointer will not be
released by releasing the pointer. So, we wrap dynamic resource allocation
with a local object.
Am my understanding right?


Yes. Just never use raw pointers as holders of a ressource: encapsulate them
in a smart pointer (e.g. boost) and your (ressource) problems should
disappear.

Kind regards
Peter
Jul 22 '05 #19
Peter Koch Larsen wrote:
Yes. Just never use raw pointers as holders of a ressource:
encapsulate them in a smart pointer (e.g. boost) and your
(ressource) problems should disappear.


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.

--
Dave O'Hearn

Jul 22 '05 #20
Dave O'Hearn wrote:
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?


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #21
Ioannis Vranos wrote:
Dave O'Hearn wrote:
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?

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?
Jul 22 '05 #22
Ioannis Vranos wrote:
Dave O'Hearn wrote:
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.
--
Dave O'Hearn

Jul 22 '05 #23
red floyd wrote:
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".


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #24
Dave O'Hearn wrote:
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?


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #25

"Dave O'Hearn" <da******@pobox.com> skrev i en meddelelse
news:11**********************@z14g2000cwz.googlegr oups.com...
Peter Koch Larsen wrote:
Yes. Just never use raw pointers as holders of a ressource:
encapsulate them in a smart pointer (e.g. boost) and your
(ressource) problems should disappear.
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

--
Dave O'Hearn

Jul 22 '05 #26
Ioannis Vranos wrote:
Ioannis Vranos wrote:

Morgan Cheng wrote:
If I implements RAII strictly, do you mean that memory leak can be
avoided totally? even exception is possibly to be thrown?

Yes, along with other resource types leaks (IP connections, file
operations etc).
All C++ standard library types support RAII (except of the C subset
types of course).
So, RAII is based on the fact that: At the end of a scope, through
normal running or exception thrown, objects in the scope will be
destructed.



Exactly.
If resource is allocated explictly, objects pointed by pointer will
not be released by releasing the pointer. So, we wrap dynamic
resource allocation with a local object.
Am my understanding right?



Yes.


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.

Jul 22 '05 #27
Peter Koch Larsen wrote:
"Dave O'Hearn" <da******@pobox.com> skrev i en meddelelse:
Peter Koch Larsen wrote:
Yes. Just never use raw pointers as holders of a ressource:
encapsulate them in a smart pointer (e.g. boost) and your
(ressource) problems should disappear.


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


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


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.

--
Dave O'Hearn

Jul 22 '05 #28
Ioannis Vranos wrote:
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.

--
Dave O'Hearn

Jul 22 '05 #29

"Dave O'Hearn" <da******@pobox.com> skrev i en meddelelse
news:11**********************@f14g2000cwb.googlegr oups.com...
Peter Koch Larsen wrote:
"Dave O'Hearn" <da******@pobox.com> skrev i en meddelelse:
> Peter Koch Larsen wrote:
>> Yes. Just never use raw pointers as holders of a ressource:
>> encapsulate them in a smart pointer (e.g. boost) and your
>> (ressource) problems should disappear.
>
> 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 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.
> 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.


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


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.

--
Dave O'Hearn

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
Jul 22 '05 #30

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

24 posts views Thread by matty | last post: by
43 posts views Thread by Sensei | last post: by
14 posts views Thread by Astley Le Jasper | last post: by
9 posts views Thread by bryonone | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.