setter for deleter in boost::shared_ptr (and alike) - c++
This is a discussion on setter for deleter in boost::shared_ptr (and alike) - c++ ; Why doesn't boost::shared_ptr<> provide a setter for the deleter when
it provides a getter? What is the use of the getter when we cannot
change it for any reason?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First ...
-
setter for deleter in boost::shared_ptr (and alike)
Why doesn't boost::shared_ptr<> provide a setter for the deleter when
it provides a getter? What is the use of the getter when we cannot
change it for any reason?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: setter for deleter in boost::shared_ptr (and alike)
Abhishek Padmanabh ha scritto:
> Why doesn't boost::shared_ptr<> provide a setter for the deleter when
> it provides a getter? What is the use of the getter when we cannot
> change it for any reason?
>
The idea is that the deleter is indissolubly connected with the way the
stored pointer has been obtained, therefore it can only be specified
together with the stored pointer (either in the constructor or in
reset()). Changing the deleter while keeping the same pointer would open
a huge hole in the safety net provided by shared_ptr. Notice that, for
the same reason, you can't even do the other way round, that is: you
can't change the pointer while keeping the same deleter.
Ganesh
PS: in case you were going to object: the overload of reset() with one
parameter is defined to be equivalent to shared_ptr(p).swap(*this) so it
will reset the deleter also.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: setter for deleter in boost::shared_ptr (and alike)
* Abhishek Padmanabh:
> Why doesn't boost::shared_ptr<> provide a setter for the deleter when
> it provides a getter?
What's provided is a pointer to the deleter function pointer or functor
object,
template<class D, class T>
D * get_deleter(shared_ptr<T> const & p);
Since there's no 'const' that pointer can used to change the deleter
function.
That's Very Bad Design(TM), both the "return pointer to innards"
signature, and because the raw pointer and deleter function work as a
unit where the deleter function should not be changed without also
changing the raw pointer, and that should be enforced by shared_ptr.
Checking TR1...
Dang! It's in TR1 too! I can't imagine what they were thinking of,
although no doubt someone will explain that (probably some silly thing
about not breaking hypothetical deleter-changing code based on
boost::shared_ptr, when that could easily be achieved by marking
get_deleter as deprecated and for good measure including it
conditionally on e.g. defined _STD_COMPATIBILITY_GET_DELETER). Let's
just hope the committee re-evaluates this "follow Boost exactly" decision.
Perhaps some bright light on the committee can also notice
* the practical utility of providing standard named destruction
functions for object and array, say, functions std::destroy and
std::destroy_array (which one can be-'friend' in classes that force
dynamic allocation by having inaccessible destructor, use address of and
place in collections, and so on).
In TR1 2.2.3.2/1 "shared_ptr destructor" the last point would then be
"- Otherwise, *this /owns/ a pointer p, and destroy(p) is called."
Then in C++0x one could write e.g.
class Foo
{
template< typename T > friend void std::destroy( T const* );
protected:
virtual ~Foo() {}
public:
Foo( int blahblah );
Foo( std::string const& s, double d );
Foo( Whatever const& );
};
int main()
{
std::shared_ptr<Foo> p( new Foo( "Hi", 3.14 ) );
//...
}
and have a guarantee that Foo instances are dynamically allocated,
useful in e.g. expression trees and other graph structures.
But perhaps the best we can hope for, and even that of very very low
probability, is a compromise where they add a 'const' to the result of
get_deleter.
> What is the use of the getter when we cannot
> change it for any reason?
A getter doesn't hurt and might be useful, e.g. for transferring the raw
pointer + deleter function to some other smart pointer.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: setter for deleter in boost::shared_ptr (and alike)
On 25 Sep, 16:48, Abhishek Padmanabh <abhishek.padman...@gmail.com>
wrote:
> Why doesn't boost::shared_ptr<> provide a setter for the deleter when
> it provides a getter? What is the use of the getter when we cannot
> change it for any reason?
{ clc++m banner removed - please remove it yourself. -mod }
The deleter is set at the constructor and reset function.
template<class Y, class D> shared_ptr(Y * p, Deleter d)
template<class Y, class D> void reset(Y * p, Deleter d)
There is no "SetDeleter" because it should be provided together with
the resource.
Generally the resource and deleter are dependent.
--------
web site
http://paginas.terra.com.br/informatica/thiago_adams/
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: setter for deleter in boost::shared_ptr (and alike)
On 25 Sep., 17:48, Abhishek Padmanabh <abhishek.padman...@gmail.com>
wrote:
> Why doesn't boost::shared_ptr<> provide a setter for the deleter when
> it provides a getter? What is the use of the getter when we cannot
> change it for any reason?
The proper function is:
template<class Y, class D>
void shared_ptr<>::reset( Y * p, D d );
see:
http://www.boost.org/libs/smart_ptr/..._ptr.htm#reset
And no, it does *not* make sense, to provide an *independent*
setter for the deleter, because the deleter is always associated
with the currently stored object, so you can provide a new
deleter whereever you can set a new resource.
Greetings from Bremen,
Daniel Krügler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: setter for deleter in boost::shared_ptr (and alike)
On 25 Sep., 20:29, "Alf P. Steinbach" <al...@start.no> wrote:
> What's provided is a pointer to the deleter function pointer or functor
> object,
>
> template<class D, class T>
> D * get_deleter(shared_ptr<T> const & p);
>
> Since there's no 'const' that pointer can used to change the deleter
> function.
>
> That's Very Bad Design(TM), both the "return pointer to innards"
> signature, and because the raw pointer and deleter function work as a
> unit where the deleter function should not be changed without also
> changing the raw pointer, and that should be enforced by shared_ptr.
>
> Checking TR1...
>
> Dang! It's in TR1 too! I can't imagine what they were thinking of,
> although no doubt someone will explain that (probably some silly thing
> about not breaking hypothetical deleter-changing code based on
> boost::shared_ptr, when that could easily be achieved by marking
> get_deleter as deprecated and for good measure including it
> conditionally on e.g. defined _STD_COMPATIBILITY_GET_DELETER). Let's
> just hope the committee re-evaluates this "follow Boost exactly" decision.
It seems a little bit unfair to assume that this is
just based on "follow Boost exactly" strategy. Currently
the draft contains several issues which are underway to be
fixed, and I did not come to the conclusion that this is
related to existing boost (or whatever based) implementations.
Yes, I think that you found an const-incorrect issue in the
draft (and TR1), but I don't think that get_deleter itself
is a design error (despite the const issue, of course). For
some words more on this theme, see below.
> Perhaps some bright light on the committee can also notice
>
> * the practical utility of providing standard named destruction
> functions for object and array, say, functions std::destroy and
> std::destroy_array (which one can be-'friend' in classes that force
> dynamic allocation by having inaccessible destructor, use address of and
> place in collections, and so on).
>
> In TR1 2.2.3.2/1 "shared_ptr destructor" the last point would then be
>
> "- Otherwise, *this /owns/ a pointer p, and destroy(p) is called."
>
> Then in C++0x one could write e.g.
>
> class Foo
> {
> template< typename T > friend void std::destroy( T const* );
> protected:
> virtual ~Foo() {}
> public:
> Foo( int blahblah );
> Foo( std::string const& s, double d );
> Foo( Whatever const& );
> };
>
> int main()
> {
> std::shared_ptr<Foo> p( new Foo( "Hi", 3.14 ) );
> //...
> }
>
> and have a guarantee that Foo instances are dynamically allocated,
> useful in e.g. expression trees and other graph structures.
I'm not sure whether I do correctly understand your proposal
or not, so please forgive the following questions, if they
seem self-explaining to you (Belief me, I don't want kidding
you!).
First, *if* I correctly understand your idea, then Foo does
not encapsulate itself stronger by using std::destroy
compared to delete, because the expression
std::destroy(new Foo(42));
would be well-formed - so what is the win compared to an
hypothetical non-existing std::destroy and
delete new Foo(42));
instead (with a publicly available destructor in this
case)? I do see the point that there cannot exist Foo
objects of automatic storage duration, but this is
similarily easy to realize via the current approach
with a friend deleter of Foo which must be provided
with the shared_ptr c'tor and reset. You can even
ensure, that no-one else but shared_ptr<Foo> can
invoke deleter:
perator()(const Foo*) by introducing
an additional friend-"connection" between the deleter
and shared_ptr.
Second, I don't see the relation between std::destroy and
the (deservedly) critized ansatz of get_deleter, would you
mind to explain? I mean, what does std::destroy solve that
exists with get_deleter? I found only a minor argument as
shown below.
> But perhaps the best we can hope for, and even that of very very low
> probability, is a compromise where they add a 'const' to the result of
> get_deleter.
Yes, this should indeed be done. And one might consider to
add another overload of the mutable type:
template<class D, class T> D* get_deleter(shared_ptr<T>& p);
get_deleter is an interesting beast. When I saw it's
declaration for the first time in the boost code, I
immediately thought of the so-called "extension-object"
pattern, see. e.g.
http://tinyurl.com/2xx2wq
(Don't be alarmed, this link will try to open a postscript file).
This might be related to the fact, that during that time
a worked for a while with Eclipse where this pattern is
extensively used. Since the static class "interface" of
the shared_ptr itself is independent on a deleter (for
some good reasons, of-course, and in contrast to e.g.
std::unique_ptr), this approach seems to be quite natural
for that use case. And because valid deleter types can be
rather different, I don't see a very much different choice
to access the deleter than this one.
There is one option - which is quite similar to get_deleter
seen from a farther point - and that would be the route which
std::function took. If you consult the section
[func.wrap.func.targ] or the synopsis of class template
function in [func.wrap.func] of N2369 you will notice that
we have there the following three members:
const std::type_info& target_type() const;
template <typename T> T* target();
template <typename T> const T* target() const;
This is effectivly equivalent to get_deleter - although
completely const-correct. The member function target_type()
does not make sense in the general case for shared_ptr,
e.g. if it will invoke delete to free it's resource, so
this asymmetry of shared_ptr compared to std::function
would be the *only* real pro-argument to consider
std::destroy instead of delete as the "natural" deleter.
Greetings from Bremen,
Daniel
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: setter for deleter in boost::shared_ptr (and alike)
* Daniel Krügler:
> On 25 Sep., 17:48, Abhishek Padmanabh <abhishek.padman...@gmail.com>
> wrote:
>> Why doesn't boost::shared_ptr<> provide a setter for the deleter when
>> it provides a getter? What is the use of the getter when we cannot
>> change it for any reason?
>
> The proper function is:
>
> template<class Y, class D>
> void shared_ptr<>::reset( Y * p, D d );
>
> see:
>
> http://www.boost.org/libs/smart_ptr/..._ptr.htm#reset
>
> And no, it does *not* make sense, to provide an *independent*
> setter for the deleter, because the deleter is always associated
> with the currently stored object, so you can provide a new
> deleter whereever you can set a new resource.
I agree, but there is an independent setter, namely get_deleter, and
it's as far from const-correct as it can be.
And that's in TR1 and in the June 2007 C++0x working draft.
One may hope the committee /makes time/ to fix this, and also to add
std::destroy and std::destroy_array (plus, while they're at it, change
the relevant wording so that we can specialize function templates in
namespace std, e.g. swap and destroy!), so that we can avoid ending up
with a standardized shared_ptr that's full of design level bugs.
Cheers,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: setter for deleter in boost::shared_ptr (and alike)
On 25 Sep., 23:24, "Alf P. Steinbach" <al...@start.no> wrote:
> I agree, but there is an independent setter, namely get_deleter, and
> it's as far from const-correct as it can be.
I agree concerning the const-correctness issue (which I
have intensively discussed in *my* reply to *your*
reply to the O.P. ;-) )
I don't think that despite this issue get_deleter is a
bad design, just because it returns an object address. Yes,
this differs from the usual copy-approach that penetrates
the STL (get_allocator(), key_comp(), value_comp()), but
note that we also have:
deleter_type& unique_ptr<T, D>::get_deleter();
const deleter_type& unique_ptr<T, D>::get_deleter() const;
Returning an lvalue like this is of-course a stronger
binding to an implementation than returning an rvalue
would be, but I similarily accept the p.o.v that the
deleter is part of the object of unique_ptr and shared_ptr
as e.g. elements of a container are (which are reachable
via their references - if we ignore std::vector<bool> for
a moment ;-)). Further-on the default deleters do not
allow a modification of the deleter state itself - even,
if a mutable reference is available. And providers of
shared_ptr deleters can easily ensure proper encapsulation
of those by a proper class design (if that it is one). I
can't remember to have seen a deleter in my life, which
would allow to influence it's actual task in this
manner. Even if it would do, I don't think that C++
is a language that would prevent one of doing so in
this rather artifical situation.
> One may hope the committee /makes time/ to fix this, and also to add
> std::destroy and std::destroy_array (plus, while they're at it, change
> the relevant wording so that we can specialize function templates in
> namespace std, e.g. swap and destroy!), so that we can avoid ending up
> with a standardized shared_ptr that's full of design level bugs.
Would you mind to explain your strong preference for
std::destroy? - I haven't understand this.
Actually I have a similar extension wish, but maybe for
different reasons:
The [memory] synopsis provides a bunch of helper functions
to support copy and fill for unconstructed items, but it
does *not* provide a std::destroy function of the signature:
template <class ForwardIterator>
void destroy(ForwardIterator first, ForwardIterator last);
which basically exists in every library implementation I
know of (of course with a proper name like _Destroy).
A typical implementation of the most general case is
a loop of type
for (; __first != __last; ++__first)
_Destroy(&*__first);
(where we are back at *your* proposed one-argument
std::destroy overload for pointers!)
The reason for my request is that implementors can do
very nice optimizations of this beast, i.e. they can
use type traits to discriminate types with trivial
destructors which end up in a no-op implementation of
the two-argument overload of destroy. Of-course from
C++0x on this could be done by every programmer - but
this would be a repeated reinvention of the wheel by
every thirdparty library which is involved in such
doings - which really sucks me (and for similar reasons
one could have rejected the uninitialized_* functions
as well - they are of similar complexity and always
use something like _Destroy internally).
What do you think?
Greetings from Bremen,
Daniel
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: setter for deleter in boost::shared_ptr (and alike)
Alf P. Steinbach ha scritto:
> * Abhishek Padmanabh:
>> Why doesn't boost::shared_ptr<> provide a setter for the deleter when
>> it provides a getter?
>
> What's provided is a pointer to the deleter function pointer or functor
> object,
>
> template<class D, class T>
> D * get_deleter(shared_ptr<T> const & p);
>
> Since there's no 'const' that pointer can used to change the deleter
> function.
It's true that with the pointer returned by get_deleter() you can call
non-const functions on the deleter, however you still can't replace it
with another (possibly unrelated) deleter and that's the important
thing, IMHO. If you don't like giving the user the chance to call
non-const functions on the deleter, simply don't declare them or make
them private.
(Of course I am not considering the evil thing of using delete in the
returned pointer, a thing that couldn't be prevented even if the pointer
was const)
Just my opinion,
Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
-
Re: setter for deleter in boost::shared_ptr (and alike)
* Daniel Krügler:
> On 25 Sep., 20:29, "Alf P. Steinbach" <al...@start.no> wrote:
>> What's provided is a pointer to the deleter function pointer or functor
>> object,
>>
>> template<class D, class T>
>> D * get_deleter(shared_ptr<T> const & p);
>>
>> Since there's no 'const' that pointer can used to change the deleter
>> function.
>>
>> That's Very Bad Design(TM), both the "return pointer to innards"
>> signature, and because the raw pointer and deleter function work as a
>> unit where the deleter function should not be changed without also
>> changing the raw pointer, and that should be enforced by shared_ptr.
>>
>> Checking TR1...
>>
>> Dang! It's in TR1 too! I can't imagine what they were thinking of,
>> although no doubt someone will explain that (probably some silly thing
>> about not breaking hypothetical deleter-changing code based on
>> boost::shared_ptr, when that could easily be achieved by marking
>> get_deleter as deprecated and for good measure including it
>> conditionally on e.g. defined _STD_COMPATIBILITY_GET_DELETER). Let's
>> just hope the committee re-evaluates this "follow Boost exactly" decision.
>
> It seems a little bit unfair to assume that this is
> just based on "follow Boost exactly" strategy. Currently
> the draft contains several issues which are underway to be
> fixed, and I did not come to the conclusion that this is
> related to existing boost (or whatever based) implementations.
Since std::tr1::shared_ptr is exactly the same as boost::shared_ptr, I
think it's justified to assume that the const-correctness error, the
same in both, is simply inherited from the Boost implementation.
> Yes, I think that you found an const-incorrect issue in the
> draft (and TR1), but I don't think that get_deleter itself
> is a design error (despite the const issue, of course). For
> some words more on this theme, see below.
The non-const-correct version is, IMO.
>> Perhaps some bright light on the committee can also notice
>>
>> * the practical utility of providing standard named destruction
>> functions for object and array, say, functions std::destroy and
>> std::destroy_array (which one can be-'friend' in classes that force
>> dynamic allocation by having inaccessible destructor, use address of and
>> place in collections, and so on).
>>
>> In TR1 2.2.3.2/1 "shared_ptr destructor" the last point would then be
>>
>> "- Otherwise, *this /owns/ a pointer p, and destroy(p) is called."
>>
>> Then in C++0x one could write e.g.
>>
>> class Foo
>> {
>> template< typename T > friend void std::destroy( T const* );
>> protected:
>> virtual ~Foo() {}
>> public:
>> Foo( int blahblah );
>> Foo( std::string const& s, double d );
>> Foo( Whatever const& );
>> };
>>
>> int main()
>> {
>> std::shared_ptr<Foo> p( new Foo( "Hi", 3.14 ) );
>> //...
>> }
>>
>> and have a guarantee that Foo instances are dynamically allocated,
>> useful in e.g. expression trees and other graph structures.
>
> I'm not sure whether I do correctly understand your proposal
> or not, so please forgive the following questions, if they
> seem self-explaining to you (Belief me, I don't want kidding
> you!).
>
> First, *if* I correctly understand your idea, then Foo does
> not encapsulate itself stronger by using std::destroy
> compared to delete, because the expression
>
> std::destroy(new Foo(42));
>
> would be well-formed - so what is the win compared to an
> hypothetical non-existing std::destroy and
>
> delete new Foo(42));
>
> instead (with a publicly available destructor in this
> case)? I do see the point that there cannot exist Foo
> objects of automatic storage duration,
Yes, and that's one main point. Given N classes with on average M
constructors each, would you rather write N friend declarations or N*M
factory functions? When it can be easy and simple, why make it
difficult and error-prone?
Another point is of course that with just a slight change of the
standard, or unqualified call of destroy so that Koenig lookup applies,
one may then easily provide a class-specific default delete operation.
> but this is
> similarily easy to realize via the current approach
> with a friend deleter of Foo which must be provided
> with the shared_ptr c'tor and reset.
No, in that case you're duplicating the specification of deleter, in
client code -- unless you go the N*M factory function route --
Umpteen times, where Umpteen is the number of instantiations of class
Foo, could be hundreds or even thousands. Duplication is evil, and
handing responsibility to client code for invoking the right Magical
Incantation every time is evil. Duplication of magical incantation
Umpteen times is Very Evil(TM): unnecessary work, and error-prone.
> You can even
> ensure, that no-one else but shared_ptr<Foo> can
> invoke deleter:
perator()(const Foo*) by introducing
> an additional friend-"connection" between the deleter
> and shared_ptr.
Not sure what you mean, technically. But anyway, restriction to a
specific smart pointer for a given class, is a separate issue. One way
is to obfuscate the use of new-expressions so that a simple "new Foo"
will not compile.
> Second, I don't see the relation between std::destroy and
> the (deservedly) critized ansatz of get_deleter, would you
> mind to explain? I mean, what does std::destroy solve that
> exists with get_deleter? I found only a minor argument as
> shown below.
What does get_deleter solve? It gives access to the destruction
function for the contained pointer, presumably in order to transfer the
raw pointer and destruction function somewhere else. And to the degree
that that's an in-practice need, it is because shared_ptr offers no way
to specify the destruction other than by providing a destruction
function dynamically, as part of the object. With std::destroy the
custom destruction function can be statically associated with the class.
And when that is known for a class, then there's no need to copy the
destruction function (pointer, functor) at run-time: it's a much cleaner
alternative for most cases I can imagine -- and I gather something
similar could even be devices for per-thread allocators. So that's the
connection, that they address the same need, but more cleanly with
std::destroy. I would want it even if there wasn't a connection,
because the lack of a means to specify destruction function statically
is a design level bug.
>> But perhaps the best we can hope for, and even that of very very low
>> probability, is a compromise where they add a 'const' to the result of
>> get_deleter.
>
> Yes, this should indeed be done. And one might consider to
> add another overload of the mutable type:
>
> template<class D, class T> D* get_deleter(shared_ptr<T>& p);
>
> get_deleter is an interesting beast. When I saw it's
> declaration for the first time in the boost code, I
> immediately thought of the so-called "extension-object"
> pattern, see. e.g.
>
> http://tinyurl.com/2xx2wq
>
> (Don't be alarmed, this link will try to open a postscript file).
>
> This might be related to the fact, that during that time
> a worked for a while with Eclipse where this pattern is
> extensively used. Since the static class "interface" of
> the shared_ptr itself is independent on a deleter (for
> some good reasons, of-course, and in contrast to e.g.
> std::unique_ptr), this approach seems to be quite natural
> for that use case. And because valid deleter types can be
> rather different, I don't see a very much different choice
> to access the deleter than this one.
A less unclean choice for that particular function would be to separate
its current to jobs: checking, and retrieving.
As member functions:
template< typename D > bool has_deleter() const; // Check.
template< typename D > D const& deleter() const; // Retrieve.
where deleter() throws or calls terminate if there is no D deleter.
An abstract deleter functor where you don't need to know the exact type
would incur about the same overhead as a shared_ptr: it would have to do
essentially the same as a shared_ptr internally. So I'm less sure about
how good or bad it would be to abstract up to that level.
> There is one option - which is quite similar to get_deleter
> seen from a farther point - and that would be the route which
> std::function took. If you consult the section
> [func.wrap.func.targ] or the synopsis of class template
> function in [func.wrap.func] of N2369 you will notice that
> we have there the following three members:
>
> const std::type_info& target_type() const;
> template <typename T> T* target();
> template <typename T> const T* target() const;
>
> This is effectivly equivalent to get_deleter - although
> completely const-correct. The member function target_type()
> does not make sense in the general case for shared_ptr,
> e.g. if it will invoke delete to free it's resource, so
> this asymmetry of shared_ptr compared to std::function
> would be the *only* real pro-argument to consider
> std::destroy instead of delete as the "natural" deleter.
Huh? I don't get what you're trying to say here.
Cheers,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Similar Threads
-
By Application Development in forum c++
Replies: 13
Last Post: 12-04-2007, 05:38 AM
-
By Application Development in forum c++
Replies: 5
Last Post: 11-26-2007, 07:53 AM
-
By Application Development in forum c++
Replies: 8
Last Post: 11-21-2007, 04:30 AM
-
By Application Development in forum c++
Replies: 1
Last Post: 09-10-2007, 07:42 AM
-
By Application Development in forum c++
Replies: 4
Last Post: 06-08-2007, 01:46 AM