Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Simple const-related question

Reply
Thread Tools

Simple const-related question

 
 
James Kanze
Guest
Posts: n/a
 
      02-19-2008
On Feb 19, 3:26 am, Jeff Schwab <(E-Mail Removed)> wrote:
> Kira Yamato wrote:
> > On 2008-02-18 20:05:51 -0500, Jeff Schwab <(E-Mail Removed)> said:


> >> I don't usually use the parentheses, either, but I guess I
> >> probably should. I also don't usually allocate objects
> >> directly with new.


> > Just curious. Instead of directly using new, what do you
> > usually use to allocate objects?


> Either the stack (sorry, "auto" storage) or one of the
> standard containers.


The stack is fine for objects whose lifetime corresponds to a
scope. It doesn't work for objects with arbitrary lifetimes.
And the standard containers all require that the object be
copiable---it's very rare for an object that you'd want to
allocate dynamically to support copy. (If it supported copy,
you'd just allocate it on the stack, passing out copies of it,
rather than maintaining that particular instance alive after
scope has been left.)

> If I have dynamically allocated objects, I generally have to
> store pointers to them somewhere anyway, so I let standard
> containers deal with managing their lifetimes.


Except that if the standard container contains pointers, it
won't (and usually shouldn't) manage their lifetime.

> For example, if I'll need an unknown quantity of Foos, I just
> create a std::list<Foo> and use its elements. Inserting or
> deleting list elements does not invalidate pointers to the
> other elements.


In my experience, most dynamically allocated objects are entity
objects. That means that they don't support copy, and so cannot
be put into a list. And of course, they're often polymorphic as
well.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
 
Jeff Schwab
Guest
Posts: n/a
 
      02-19-2008
James Kanze wrote:
> On Feb 19, 3:26 am, Jeff Schwab <(E-Mail Removed)> wrote:
>> Kira Yamato wrote:
>>> On 2008-02-18 20:05:51 -0500, Jeff Schwab <(E-Mail Removed)> said:

>
>>>> I don't usually use the parentheses, either, but I guess I
>>>> probably should. I also don't usually allocate objects
>>>> directly with new.

>
>>> Just curious. Instead of directly using new, what do you
>>> usually use to allocate objects?

>
>> Either the stack (sorry, "auto" storage) or one of the
>> standard containers.

>
> The stack is fine for objects whose lifetime corresponds to a
> scope. It doesn't work for objects with arbitrary lifetimes.
> And the standard containers all require that the object be
> copiable---it's very rare for an object that you'd want to
> allocate dynamically to support copy. (If it supported copy,
> you'd just allocate it on the stack, passing out copies of it,
> rather than maintaining that particular instance alive after
> scope has been left.)
>
>> If I have dynamically allocated objects, I generally have to
>> store pointers to them somewhere anyway, so I let standard
>> containers deal with managing their lifetimes.

>
> Except that if the standard container contains pointers, it
> won't (and usually shouldn't) manage their lifetime.


Yes, it should. It shouldn't manage the lifetimes of the objects
pointed to by those pointers. But anyway, I didn't mean that I store
pointers in the containers, I meant that I store the objects directly in
the containers.


>> For example, if I'll need an unknown quantity of Foos, I just
>> create a std::list<Foo> and use its elements. Inserting or
>> deleting list elements does not invalidate pointers to the
>> other elements.

>
> In my experience, most dynamically allocated objects are entity
> objects. That means that they don't support copy, and so cannot
> be put into a list.


The abstract (interface) type can't be copied, but the concrete type
generally can.

> And of course, they're often polymorphic as
> well.


If a factory may need to generate any of ten different concrete types
implementing a particular interface, then it can use ten different lists:

struct obj_interface {
// ...
};

struct obj_factory {

typedef obj_interface* obj_pointer;

obj_pointer create(criteria);

private:
std::list<concrete_obj_a> a_list_;
std::list<concrete_obj_b> b_list_;
// ...
};
 
Reply With Quote
 
 
 
 
James Kanze
Guest
Posts: n/a
 
      02-19-2008
On Feb 19, 6:57 pm, Jeff Schwab <(E-Mail Removed)> wrote:
> James Kanze wrote:
> > On Feb 19, 3:26 am, Jeff Schwab <(E-Mail Removed)> wrote:
> >> If I have dynamically allocated objects, I generally have to
> >> store pointers to them somewhere anyway, so I let standard
> >> containers deal with managing their lifetimes.


> > Except that if the standard container contains pointers, it
> > won't (and usually shouldn't) manage their lifetime.


> Yes, it should. It shouldn't manage the lifetimes of the objects
> pointed to by those pointers.


Yes. I should have been more precise. That's what I meant, of
course.

> But anyway, I didn't mean that I store pointers in the
> containers, I meant that I store the objects directly in the
> containers.


Which is where you loose me, since generally, if you can copy an
object, there's no need to allocate it dynamically. And if you
cannot copy it, you can't store it directly in the container.

> >> For example, if I'll need an unknown quantity of Foos, I just
> >> create a std::list<Foo> and use its elements. Inserting or
> >> deleting list elements does not invalidate pointers to the
> >> other elements.

>
> > In my experience, most dynamically allocated objects are entity
> > objects. That means that they don't support copy, and so cannot
> > be put into a list.


> The abstract (interface) type can't be copied, but the
> concrete type generally can.


Since when? Identity is identity.

> > And of course, they're often polymorphic as
> > well.


> If a factory may need to generate any of ten different concrete types
> implementing a particular interface, then it can use ten different lists:


Which does what, other than make the code more complicated?
(And of course, the derived types may be derived by the
application.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
Jeff Schwab
Guest
Posts: n/a
 
      02-20-2008
James Kanze wrote:
> On Feb 19, 6:57 pm, Jeff Schwab <(E-Mail Removed)> wrote:
>> James Kanze wrote:
>>> On Feb 19, 3:26 am, Jeff Schwab <(E-Mail Removed)> wrote:
>>>> If I have dynamically allocated objects, I generally have to
>>>> store pointers to them somewhere anyway, so I let standard
>>>> containers deal with managing their lifetimes.

>
>>> Except that if the standard container contains pointers, it
>>> won't (and usually shouldn't) manage their lifetime.

>
>> Yes, it should. It shouldn't manage the lifetimes of the objects
>> pointed to by those pointers.

>
> Yes. I should have been more precise. That's what I meant, of
> course.
>
>> But anyway, I didn't mean that I store pointers in the
>> containers, I meant that I store the objects directly in the
>> containers.

>
> Which is where you loose me, since generally, if you can copy an
> object, there's no need to allocate it dynamically.


Client code can't copy the object (except through object->clone() or the
like), because the client has only a pointer to some abstract base type.
Within the factory that creates the objects, though, there's no mystery
about the exact derived types involved, so they can be created, copied,
or what have you. The factory has to allocate the object dynamically so
that the object will continue to exist after the factory function
returns. The alternative, which I posted elsewhere in this thread, is
for the client code to give the factory a "receiver" to which the
object's address can be passed. The code in the receiver completes
before the factory function returns, and therefore before the object
goes out of scope.


> And if you
> cannot copy it, you can't store it directly in the container.
>
>>>> For example, if I'll need an unknown quantity of Foos, I just
>>>> create a std::list<Foo> and use its elements. Inserting or
>>>> deleting list elements does not invalidate pointers to the
>>>> other elements.
>>> In my experience, most dynamically allocated objects are entity
>>> objects. That means that they don't support copy, and so cannot
>>> be put into a list.

>
>> The abstract (interface) type can't be copied, but the
>> concrete type generally can.

>
> Since when? Identity is identity.


Since ever. I don't know what you mean by "identity is identity."
Whether you can copy a particular object almost always depends on
whether you have a pointer to its most-derived type, or to some abstract
base.

The factory that creates objects implementing a particular interface
knows the derived types directly; if it didn't, it couldn't instantiate
them. There's no reason the factory can't copy those objects at will.


>>> And of course, they're often polymorphic as
>>> well.

>
>> If a factory may need to generate any of ten different concrete types
>> implementing a particular interface, then it can use ten different lists:

>
> Which does what, other than make the code more complicated?
> (And of course, the derived types may be derived by the
> application.)


It does not (IMO) make the code more complicated. The factory no longer
needs to call new or delete directly, no longer needs an explicitly
declared destructor to delete the objects, and has immediate access to
all objects of a particular derived type.

Suppose a factory stores a single vector of pointers-to-Abstract, rather
than a separate list for each derived type. Now suppose the factory
needs to access all objects of some particular derived type. The
popular solution is to walk through the entire vector, checking each
element's dynamic type with dynamic_cast. Slow and ugly.
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      02-21-2008
On Feb 21, 12:05 am, Jeff Schwab <(E-Mail Removed)> wrote:
> James Kanze wrote:
> > On Feb 19, 6:57 pm, Jeff Schwab <(E-Mail Removed)> wrote:
> >> James Kanze wrote:
> >>> On Feb 19, 3:26 am, Jeff Schwab <(E-Mail Removed)> wrote:
> >>>> If I have dynamically allocated objects, I generally have to
> >>>> store pointers to them somewhere anyway, so I let standard
> >>>> containers deal with managing their lifetimes.


> >>> Except that if the standard container contains pointers, it
> >>> won't (and usually shouldn't) manage their lifetime.


> >> Yes, it should. It shouldn't manage the lifetimes of the objects
> >> pointed to by those pointers.


> > Yes. I should have been more precise. That's what I meant, of
> > course.


> >> But anyway, I didn't mean that I store pointers in the
> >> containers, I meant that I store the objects directly in the
> >> containers.


> > Which is where you loose me, since generally, if you can copy an
> > object, there's no need to allocate it dynamically.


> Client code can't copy the object (except through
> object->clone() or the like), because the client has only a
> pointer to some abstract base type.


That's one situation, appropriate for some applications, but not
everywhere. What happens with the template method pattern, for
example, where the client has to derive himself in order for the
pattern to work. Most of the time, the "client" is responsible
for creating the object.

(I put "client" in quotes, because I'm not sure the word is
really appropriate. Most such objects in my applications are at
the application level---there is no higher level which can be
considered a "client", for which they are a service provider.)

> Within the factory that creates the objects, though, there's
> no mystery about the exact derived types involved, so they can
> be created, copied, or what have you. The factory has to
> allocate the object dynamically so that the object will
> continue to exist after the factory function returns. The
> alternative, which I posted elsewhere in this thread, is for
> the client code to give the factory a "receiver" to which the
> object's address can be passed. The code in the receiver
> completes before the factory function returns, and therefore
> before the object goes out of scope.


But the receiver has to know the exact type, which sort of
defeats the role of the factory.

At any rate, I don't see what this buys you. Instead of just
calling delete (on a pointer to the base, or more often, on
this), the code has to find the correct type, to find the
receiver, and remove the object from the receiver. This sounds
like a lot of extra complication (and obfuscation) for nothing.

> > And if you cannot copy it, you can't store it directly in
> > the container.


> >>>> For example, if I'll need an unknown quantity of Foos, I just
> >>>> create a std::list<Foo> and use its elements. Inserting or
> >>>> deleting list elements does not invalidate pointers to the
> >>>> other elements.
> >>> In my experience, most dynamically allocated objects are entity
> >>> objects. That means that they don't support copy, and so cannot
> >>> be put into a list.


> >> The abstract (interface) type can't be copied, but the
> >> concrete type generally can.


> > Since when? Identity is identity.


> Since ever. I don't know what you mean by "identity is identity."


Just what I said. An entity object has identity. You can't
copy it---two different objects are two different objects, and
one can't replace the other.

The typical example I use is that of a monetary amount and a
bank account. A monetary amount is a value. You can (and
usually do) copy and assign it. You practically never allocate
it dynamically. A bank account is an entity. A copy of my bank
account is not my bank account, and if you're crediting a
monetary amount to it, you have to do it on the specific object,
not some copy which happens to be equal.

Normally, entity objects do NOT support copy and assignment.
This isn't always strictly true for copy---transaction
management often involves copies in order to implement roll
back. But I've never seen one which supported assignment---in
practice, assignment and polymorphism don't work well together.

> Whether you can copy a particular object almost always depends
> on whether you have a pointer to its most-derived type, or to
> some abstract base.


Whether you can copy a particular object depends on whether it
supports copy. Most polymorphic objects don't (or shouldn't).
And of course, if the object is to be kept in a container, it
needs to support assignment as well.

> The factory that creates objects implementing a particular
> interface knows the derived types directly; if it didn't, it
> couldn't instantiate them. There's no reason the factory
> can't copy those objects at will.


Except that by design, the object doesn't support copy and
assignment.

(I have one or two cases in my code where an object supports
copy only because I need to bind it to a reference in some
cases. In such cases, the copy constructor only works if the
object has just been created; once it has been used for anything
else, calling the copy constructor will cause an assertion
failure. Such a scheme could be used in your case. But again:
why?)

> >>> And of course, they're often polymorphic as well.


> >> If a factory may need to generate any of ten different
> >> concrete types implementing a particular interface, then it
> >> can use ten different lists:


> > Which does what, other than make the code more complicated?
> > (And of course, the derived types may be derived by the
> > application.)


> It does not (IMO) make the code more complicated. The factory
> no longer needs to call new or delete directly, no longer
> needs an explicitly declared destructor to delete the objects,
> and has immediate access to all objects of a particular
> derived type.


Whoever decides to delete the object has to know the most
derived type, in order to find the appropriate container.
That's an enormous complication, and goes against all of the
principles of OO design. And it doesn't buy you anything that I
can see---what's the difference between calling delete (which
every C++ programmer knows will delete the object), and calling
erase on some container (where the relationship between the
pointer one has and the element in the container that is being
deleted may not be obvious)? I'd call using containers for this
obfuscation and additional complication.

And of course, you're not always using a factory---things like
the template method pattern are quite popular in GUI libraries,
for example.

> Suppose a factory stores a single vector of
> pointers-to-Abstract, rather than a separate list for each
> derived type. Now suppose the factory needs to access all
> objects of some particular derived type.


Why would it need to do that? Is it a factory, or is it
something else---a factory has nothing to do with the object
once it has created it.

> The popular solution is to walk through the entire vector,
> checking each element's dynamic type with dynamic_cast.


The usual solution is to forget the derived type entirely once
the object has been created. There are some cases where
dynamic_cast is appropriate, but not very many. The whole point
of derivation (in this case) is that the derived type isA base
type---you need to know the derived type in order to create the
object, but once that's done, you have a base, and that's all
you want to know. (There are exceptions, of course, but they
aren't that frequent.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Plz, a simple answer to a simple question about IP addresses MeekiMoo Computer Support 0 07-28-2009 08:10 AM
Simple region code question... simple answer?? joseph.greer@gmail.com DVD Video 7 01-26-2007 09:07 PM
Simple Question - Simple Answer? Daniel Frey XML 4 01-12-2005 04:25 PM
Re: Simple Simple question!!! Kevin Spencer ASP .Net 0 06-25-2004 05:25 PM
Re: Simple Simple question!!! ashelley@inlandkwpp.com ASP .Net 0 06-25-2004 04:18 PM



Advertisments