mutable: why it's in the language

196 просмотров
Перейти к первому непрочитанному сообщению

Yuri Victorovich

не прочитано,
2 авг. 2003 г., 09:42:5202.08.2003
My question is:
can anyone provide an example when mutable will fit into nice and logical design
of objects ?

I think it's in the language just to enable certain ways of hacking of
existing code.

My rationale: if it's the concept of const objects that's what this means: constant.
Why to ever open the back door and allow to change field marked as "mutable" ?

Thanx,
Yuri.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

John G Harris

не прочитано,
2 авг. 2003 г., 15:57:2002.08.2003
In article <d2800884.0308...@posting.google.com>, Yuri
Victorovich <yu...@tsoft.com> writes

>My question is:
>can anyone provide an example when mutable will fit into nice and
>logical design
>of objects ?
>
>I think it's in the language just to enable certain ways of hacking of
>existing code.
>
>My rationale: if it's the concept of const objects that's what this
>means: constant.
>Why to ever open the back door and allow to change field marked as "mutable" ?

mutable allows an object to change things that aren't visible to
outsiders. The usual example is a cache of answers that are expensive to
calculate. There's nothing back door about this.

Of course, it can be used badly but you wouldn't want to do that, would
you ?

John
--
John Harris
mailto:jo...@jgharris.demon.co.uk

Sebastian Moleski

не прочитано,
2 авг. 2003 г., 16:02:4002.08.2003
"Yuri Victorovich" <yu...@tsoft.com> wrote in message
news:d2800884.0308...@posting.google.com...

> My question is:
> can anyone provide an example when mutable will fit into nice and logical
design
> of objects ?
>
> I think it's in the language just to enable certain ways of hacking of
> existing code.
>
> My rationale: if it's the concept of const objects that's what this means:
constant.
> Why to ever open the back door and allow to change field marked as "mutable" ?

Pretty much the only time I use mutable is with thread synchronization objects.
If I create a class where I want serialized access, for example, I add a mutable
Mutex member to the class. The problem is that the "lock" and "unlock" functions
of a Mutex class are usually not const. Now, locking and unlocking the mutex has
no affect on the external status of the object so mutable is fine here.

sm

Andy Sawyer

не прочитано,
2 авг. 2003 г., 16:03:2802.08.2003
In article <d2800884.0308...@posting.google.com>,
on 2 Aug 2003 09:42:52 -0400,
yu...@tsoft.com (Yuri Victorovich) wrote:

> My question is:
> can anyone provide an example when mutable will fit into nice and
> logical design of objects ?

mutable allows us to differentiate between "logical" and "bitwise"
const-ness. It's often (but not always) an implementation technique,
rather than a "logical design" technique.

> I think it's in the language just to enable certain ways of hacking of
> existing code.

It enables certain techniques which are otherwise available, but
syntactically awkward.

> My rationale: if it's the concept of const objects that's what this
> means: constant.
>
> Why to ever open the back door and allow to change field marked as
> "mutable" ?

It's not a "back door" - it's a decision made by a class designer. If
you don't need mutable, don't use it and that door will not be opened.

As for an example of when it can be useful,
consider:

class foo
{
// ...
public:
int result() const
{
return do_some_time_consuming_calculation();
}
};


Note that result doesn't actually change the state of the object, it
merely tells us something about it.

In some cases, it might be that cacheing the value of result can gain us
considerable performance improvements - we're not logically affecting
the state of the object, but we do need to affect it in a "bitwise"
fashion, to cache the result. Without mutable, we might implement this
as something like:

class foo
{
struct result_t {
bool cached_;
int value_;
result_t() : cached_(false)
};

result_t *result_;
public:
foo() : result_( new result_t ) {}
~foo() { delete result_; }
int result() const
{
if( !result_->cached_ )
{
result_->value__ = do_some_time_consuming_calculation();
result_->cached_ = true;
}
return result_->value_;
}
};

If we modify the object in some way that the calculation is invalidated,
we set result_->result_cached_ to false, and the recalculate when necessary.

This works, but is tedious and error prone (fortunatly, I checked
through the code again before I posted it and spotted an error;). It
introduces an extra dynamic allocation, which may be an issue. Also,
compiler generated copy & assignment operators no longer work
correctly. If we introduce mutable, then we can implement this as:

class foo
{
// ...
mutable result_t result_;
public:
int result() const
{
if( !result_.cached_ )
{
result_.value_ = do_some_time_consuming_calculation();
result_.cached_ = true;
}
return result_.value_;
}
};


An specific example of where this technique is useful is calculating
a CRC or MD5 hash of a block of data. Performing that calculation does
not, in itself, affect the *logical* state of the object but caching the
result can (in some cases) bring considerable performance benefits
(especially if you're working in an "every clock cycle counts"
environment). So being able to change the bitwise state of the object is
useful. mutable is one of those things that you don't need often, but
when you do need it, it can be incredibly handy.

Regards,
Andy S
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there first,
and is waiting for it." -- Terry Pratchett, Reaper Man

Alf P. Steinbach

не прочитано,
2 авг. 2003 г., 18:18:4302.08.2003
On 2 Aug 2003 09:42:52 -0400, yu...@tsoft.com (Yuri Victorovich) wrote:

>My question is:
>can anyone provide an example when mutable will fit into nice and logical design
>of objects ?
>
>I think it's in the language just to enable certain ways of hacking of
>existing code.
>
>My rationale: if it's the concept of const objects that's what this means: constant.
>Why to ever open the back door and allow to change field marked as "mutable" ?

Generally 'const' indicates _logical_ constness: that the client code
cannot change the externally observable state of an object. But it does
not even enforce that. Enforcing that is up to the programmer. What it
does enforce is just to prohibit direct changes of the member variables
of a 'const' object. Often that is enough (indirection can break this).

However, especially for efficiency, an object might need to change its
concrete (implementation) state, e.g. in order to cache a result. One
way to do that is via indirection. To avoid such indirection, which is
not desirable when optimizing for efficiency, one can use 'mutable'.

An example might be a 'const' member function that returns the inverse
of a matrix. Computing the inverse is a potentially time-consuming
operation, and so it makes sense to cache that result in the object.
The cache member variable would have to be 'mutable'.

Another example from some years ago, lazy evaluation. In interfacing
Java to C++ there might be a need for both narrow and wide character
representation of a Java string passed to the C++ code. The Java
string is itself represented by a handle to some representation, I
think it was UTF-8 -- but that doesn't matter.

Now one way to go about this is to let the client code manage various
copies, which it obtains via functions such as


std::string stringFrom( JavaStringHandle h );
std::wstring wstringFrom( JavaStringHandle h );


That way is inefficient in both time and space, and since the
representations are possibly lossy the client code will have to keep
the handles around.

An alternative is to wrap the low-level handle in an object that
represents a logically constant string:


class JString
{
public:
JString( JavaStringHandle handle );
char const* narrowString() const;
wchar_t const* wideString() const;
...
};

Here the client code can use a single JString object. But
internally in that object it would be wasteful to allocate buffers
for both wide and narrow strings on construction, since for a
particular string object the client code might end up using only
the narrow character epresentation, or the wide character
representation. Thus, as a natural optimization these buffers
should be allocated only when needed, which means they must be
'mutable'.

Jakob Bieling

не прочитано,
2 авг. 2003 г., 18:19:1002.08.2003
"Yuri Victorovich" <yu...@tsoft.com> wrote in message
news:d2800884.0308...@posting.google.com...
> My question is:
> can anyone provide an example when mutable will fit into nice and logical
design
> of objects ?
>
> I think it's in the language just to enable certain ways of hacking of
> existing code.
>
> My rationale: if it's the concept of const objects that's what this means:
constant.
> Why to ever open the back door and allow to change field marked as
"mutable" ?


const does not necessarily mean all bytes of the class will stay the
same. const means the state of the class does not change. Suppose you have a
class with two members, one holding your data (say, and int) and another one
that encapsulates an OS dependant synchronisation object in a multi-threaded
environment. This class then also has two member functions that let you
retrieve or set the data value. Obviously, if you call the set function, you
change the state of the class, so 'set_data' cannot be const. On other other
hand, 'get_data' should be const, since all you do is retrieve the value and
leave the class in the same state. Both function use 'sync_obj' to
synchronize the access to the variable, in case two threads try to set/get
the data at the same time. Below is an implementation of what it might look
like (note, get and set functions used in this way are poor, but this is
only to demonstrate the use of mutable, and nothing else):

class mutable_test
{
int data;
sync sync_obj;
public:

void set_data (int i)
{
sync_obj.lock ();
data = i;
sync_obj.unlock ();
}


int get_data () const
{
sync_obj.lock ();
int i = data;
sync_obj.unlock ();
return i;
}
};

The functions 'lock' and 'unlock' are, of course, not const, because
they do modify the state of the whole class. So you see, you would not be
able to make use of synchronisation *and* keep 'get_data' const, because
const member functions can not modify member variables or call non-const
member function of member variables that are classes/structs.

That is where the mutable keyword comes into play. In the above class,
you make 'sync_obj' mutable, so you can call 'lock' and 'unlock' on that
object, even though you are in a const function. This /does/ make sense,
because when you call 'get_data' you do /not/ change the state of your
'mutable_test' object.

hth
--
jb

(replace y with x if you want to reply by e-mail)

Nicolas Fleury

не прочитано,
2 авг. 2003 г., 18:21:2702.08.2003
Yuri Victorovich wrote:
> My question is:
> can anyone provide an example when mutable will fit into nice and logical design
> of objects ?
>
> I think it's in the language just to enable certain ways of hacking of
> existing code.
>
> My rationale: if it's the concept of const objects that's what this means: constant.
> Why to ever open the back door and allow to change field marked as "mutable" ?
>
> Thanx,
> Yuri.

Const means an object is logically const. For example, suppose you have
a const object shared by multiple threads; you might need a mutex in the
object and this mutex might need, depending on API, to be mutable.
Doing a const_cast on it might be asking for trouble, because without
mutable, the entire object could be put in read-only memory. You don't
need mutable often, but the reason it has been added in the language is
because when you need it, you really need it.

Regards,
Nicolas

Bo Persson

не прочитано,
2 авг. 2003 г., 18:24:3202.08.2003

"Yuri Victorovich" <yu...@tsoft.com> skrev i meddelandet
news:d2800884.0308...@posting.google.com...

> My question is:
> can anyone provide an example when mutable will fit into nice and
logical design
> of objects ?
>
> I think it's in the language just to enable certain ways of hacking
of
> existing code.
>
> My rationale: if it's the concept of const objects that's what this
means: constant.
> Why to ever open the back door and allow to change field marked as
"mutable" ?

Because an object can be conceptually const in its interface, but
still update some of its internal representation when needed. For
example, if some value is expensive to compute, like the average of a
range of constant values, the manager object could postpone the
calculations until someone asks for the average, if ever. Once it is
calculated, the result can be cached in a mutable member.


Bo Persson
bo...@telia.com

Francis Glassborow

не прочитано,
2 авг. 2003 г., 18:25:2202.08.2003
In message <d2800884.0308...@posting.google.com>, Yuri
Victorovich <yu...@tsoft.com> writes

>My question is:
>can anyone provide an example when mutable will fit into nice and logical design
>of objects ?

The classic example is caching a floating point value for a rational
number type. Working in numerics I would not want that evaluated unless
it were needed, but once it had been evaluated I would not want the
result re-evaluated.

There are many cases where there are advantages in caching results for
an object that is declared as const.

>
>I think it's in the language just to enable certain ways of hacking of
>existing code.

WG21 does not introduce new things at the cost of a whole keyword to
support hacking.


>
>My rationale: if it's the concept of const objects that's what this means: constant.
>Why to ever open the back door and allow to change field marked as "mutable" ?

Because an object can have a const immutable state even though we want
to store cached information in it.

See the C++ Programming Language 3ed page 232.

--
ACCU Spring Conference 2003 April 2-5
The Conference you should not have missed
ACCU Spring Conference 2004 Late April
Francis Glassborow ACCU

Thomas A. Horsley

не прочитано,
2 авг. 2003 г., 18:25:4802.08.2003
>can anyone provide an example when mutable will fit into nice and logical
>design of objects ?

I think the idea is that it is mostly for cache-like members, so you
can do things like remember previous results even when operating on
logically const objects. For example:

class AnswerComplicatedQuestion {
public:

int
DigUpHardToComputeAnswer(int inval) const;

private:

mutable int last_query;
mutable int last_result;
};


int
AnswerComplicatedQuestion::DigUpHardToComputeAnswer(int inval) const {
if (inval == last_query) {
return last_result;
}
last_query = inval;
// Long complicated algorithm to generate new result goes here...
last_result = ...whatever
return last_result;
}

Of course, it is also useful for hacking. I often wish compilers came with
an option to treat all members as mutable, so that annoying "const" thing
would stay out of my hair :-).
--
>>==>> The *Best* political site <URL:http://www.vote-smart.org/> >>==+
email: Tom.H...@worldnet.att.net icbm: Delray Beach, FL |
<URL:http://home.att.net/~Tom.Horsley> Free Software and Politics <<==+

Marco Manfredini

не прочитано,
2 авг. 2003 г., 18:26:1302.08.2003
Yuri Victorovich wrote:

> My question is:
> can anyone provide an example when mutable will fit into nice and
> logical design of objects ?

Any example where a members actual value doesn't contribute to the
observable state of the object fits. Examples are:

*) the object possesses a reference counter, which can be changed if a
pointer to the object is copied or disposed. Changing the reference
count doesn't change the behaviour.

*) The object is an access point to some data which is expensive to look
up (or load from disk). The object may *cache* the access to the data
item, thus allowing it to purge and reload the item if memory
conditions require it. The "caching" part is mutable, since it doesn't
contribute to the observable state (unless you count the fact, that
data access speed differs).

>
> I think it's in the language just to enable certain ways of hacking of
> existing code.

How is the supposed to be understood? Somebody takes exisiting code,
makes everything const there and then mutable again?

>
> My rationale: if it's the concept of const objects that's what this
> means: constant. Why to ever open the back door and allow to change
> field marked as "mutable" ?

Because "const" doesn't mean "read only memory", but "inmutable with
respect to the observable state"

Marco
--
The text above is a result of a bug in my newsreader and I take no
responsibility for this text appearing in my post.

Le Chaud Lapin

не прочитано,
2 авг. 2003 г., 22:07:4302.08.2003
yu...@tsoft.com (Yuri Victorovich) wrote in message news:<d2800884.0308...@posting.google.com>...

> My question is:
> can anyone provide an example when mutable will fit into nice and logical design
> of objects ?
>
> I think it's in the language just to enable certain ways of hacking of
> existing code.
>
> My rationale: if it's the concept of const objects that's what this means: constant.
> Why to ever open the back door and allow to change field marked as "mutable" ?

A while ago I decided to make my own C++ library which included
List<>, Associative_List<>, etc.

Unlike STL, I kept an iterator internal to my List<> class and let
functions move it around to access elements of the list as necessary:

list.marker_home(); // puts iterator (marker) at beginning of list.

Keeping the marker internal turns out to be very convenient, but it
poses a problem when you want to pass a List<> by reference while
preventing the receiving function from modifying the list:

void foo (const List<Integer> &list); // foo should not change list
proper

What is expressed here is that 'foo' should not change the fundamental
structure of the list. However, it should be allowed to move the
marker. As I thought about this peculiar situation, I remember
thinking, "Too bad there isn't a way to make a portion of the class
mutable even though the whole thing is declared 'const'...."

You can imagine my delight when I discovered the keyword 'mutable' a
few days later. The declaration of my iterator inside of List<> now
looks like this:

mutable struct Marker
{
Node *pointer;
unsigned int index;
} marker;

This expresses exactly the idea I had in mind: the structure of the
List<>, which excludes the iterator (marker) in an abstract sense,
should not change, whereas marker movement for iteration over the
elements should always be permissible.

-Chaud Lapin-

Roy Smith

не прочитано,
2 авг. 2003 г., 22:08:4502.08.2003
yu...@tsoft.com (Yuri Victorovich) wrote:
> My question is:
> can anyone provide an example when mutable will fit into nice and logical
> design of objects?

Mutable is an exception to declaring a function const. Const says, "If
you call this method, I promise the externally visible state of the
object won't change".

The compiler enforces const by not letting you change any data members
of the object, but in some cases, this is too strict. There may be
members which don't affect the externally visible state. The compiler
isn't smart enough to know which members only affect internal state and
which affect externally visible state, so it's limited to enforcing "no
changes at all", unless you declare a member mutable.

Mutable says, "I promise that even if you change the value of this
member, there is no way anybody calling a method of this object can
detect the change".

The most common example are caches. An external caller of a method gets
back the same result regardless of whether it's computed on the fly or
simply retrieved from a cache.

> My rationale: if it's the concept of const objects that's what this means:
> constant.

Perhaps a better way to think of const is "The externally observable
behavior is constant".

Dhruv

не прочитано,
3 авг. 2003 г., 05:11:4903.08.2003
On Sat, 02 Aug 2003 09:42:52 -0400, Yuri Victorovich wrote:

> My question is:
> can anyone provide an example when mutable will fit into nice and logical design
> of objects ?

For the design design decisions and rationale behind any feature in the
language, please consult D&E written by Bjarne Stroustrup.


Regards,
-Dhruv.

Alf P. Steinbach

не прочитано,
3 авг. 2003 г., 18:31:4803.08.2003
On 2 Aug 2003 22:07:43 -0400, unorigina...@yahoo.com (Le Chaud Lapin) wrote:

>yu...@tsoft.com (Yuri Victorovich) wrote in message news:<d2800884.0308...@posting.google.com>...
>> My question is:
>> can anyone provide an example when mutable will fit into nice and logical design
>> of objects ?
>>
>> I think it's in the language just to enable certain ways of hacking of
>> existing code.
>>
>> My rationale: if it's the concept of const objects that's what this means: constant.
>> Why to ever open the back door and allow to change field marked as "mutable" ?
>
>A while ago I decided to make my own C++ library which included
>List<>, Associative_List<>, etc.
>
>Unlike STL, I kept an iterator internal to my List<> class and let
>functions move it around to access elements of the list as necessary:
>
>list.marker_home(); // puts iterator (marker) at beginning of list.
>
>Keeping the marker internal turns out to be very convenient,

How?

>but it poses a problem when you want to pass a List<> by reference while
>preventing the receiving function from modifying the list:
>
>void foo (const List<Integer> &list); // foo should not change list
>proper

This is a good argument _against_ having a built-in cursor in
a list.

In some cases there are also good arguments _for_ having a built-in
cursor. For example, when using a cursor gap implementation there
should be only one cursor, ever, that permits insertion. In that
case, however, any number of read-only cursors (or in C++ terminology,
iterators) is OK, which would match well with the 'foo' requirements,
with no need for 'mutable' members.


>What is expressed here is that 'foo' should not change the fundamental
>structure of the list. However, it should be allowed to move the
>marker. As I thought about this peculiar situation, I remember
>thinking, "Too bad there isn't a way to make a portion of the class
>mutable even though the whole thing is declared 'const'...."
>
>You can imagine my delight when I discovered the keyword 'mutable' a
>few days later. The declaration of my iterator inside of List<> now
>looks like this:
>
>mutable struct Marker
>{
> Node *pointer;
> unsigned int index;
>} marker;
>
>This expresses exactly the idea I had in mind: the structure of the
>List<>, which excludes the iterator (marker) in an abstract sense,
>should not change, whereas marker movement for iteration over the
>elements should always be permissible.

IMO that is abuse of 'mutable'.

In this situation 'foo' changes an externally observable part of the
state of the object.

It's doubtful whether direct language support will ever be available,
in any language, for enforcing the idea that a given _part_ of an
object should be non-modifiable in a given context. When such a
constraint is desirable it must be implemented at a higher level.
E.g. by separating the part in question from the rest of the object.

Le Chaud Lapin

не прочитано,
4 авг. 2003 г., 18:29:1804.08.2003
al...@start.no (Alf P. Steinbach) wrote in message news:<3f2d42d5....@News.CIS.DFN.DE>...

> On 2 Aug 2003 22:07:43 -0400, unorigina...@yahoo.com (Le Chaud Lapin) wrote:
>
> >yu...@tsoft.com (Yuri Victorovich) wrote in message news:<d2800884.0308...@posting.google.com>...
> >> My question is:
> >> can anyone provide an example when mutable will fit into nice and logical design
> >> of objects ?
> >>
> >> I think it's in the language just to enable certain ways of hacking of
> >> existing code.
> >>
> >> My rationale: if it's the concept of const objects that's what this means: constant.
> >> Why to ever open the back door and allow to change field marked as "mutable" ?
> >
> >A while ago I decided to make my own C++ library which included
> >List<>, Associative_List<>, etc.
> >
> >Unlike STL, I kept an iterator internal to my List<> class and let
> >functions move it around to access elements of the list as necessary:
> >
> >list.marker_home(); // puts iterator (marker) at beginning of list.
> >
> >Keeping the marker internal turns out to be very convenient,
>
> How?

It allows me to made ad-hoc containers without having to define
iterators to go along with them. For example:

extern Shared<Associative_List<Digital_Address, Key_Pair> >
digital_key_map;
extern Shared<Associative_List<Textual_Address, Key_Pair> >
textual_key_map;
extern Shared<List<Network_Interface::Group> > network_interface_set;

In each of these data structures, the iterator is internal. It would
be irksome is to have to declare an iterator every time I made a
non-trivial data structure using a container:

Associative_List<Textual_Address, Key_Pair> >::Iterator my_iterator;

Then I would have to initialize it, then let it do the work. If the
iterator's state is significant, I would need a second global data
object (the iterator) for each my global container objects.

It becomes even more annoying when I am about to do a triple-nested
iteration over containers:

List<String> a, b, c;

if (a.marker_home())
do
// do some work with a
if (b.marker_home()
do
// do some work with b
while (b.marker_next());
if (c.marker_home()
do
// do some work with c
while (c.marker_next());
while (a.marker_next():

The code becomes cluttered with iterator declarations. With the
external-cursor model, I would have to declare iterators for each
iteration every time I decided to iterate over a list. If the
containers are non-trivial as in...

Associative_List<String, List<Associative_List<Digital_Address,
Cipher_Rijndael::Key> > > x;

... then making the iterator for 'x', and each of the containers that
provide the structure of x, would be a nuissance...

Associative_List<String, List<Associative_List<Digital_Address,
Cipher_Set::Symmetric_Cipher::Key> > >::iterator i1;

List<Associative_List<Digital_Address, Cipher_Rijndael::Key>
>::iterator i2;

Associative_List<Digital_Address, Cipher_Rijndael::Key>::iterator i3;

... and it still remains to initialize the iterators.

With my method, I simply make 'x' as above then write:

if (x.marker_home()) // returns true if x is not empty
do
{
x.LHE()...// yields the left-hand-element of row of x...
x.RHE()...// yields the right-hand-element of row of x.
//..note that right-hand-element is itself a List<>
if (x.RHE().marker_home())
do
x.RHE().marked_element(); // yields current element of List<>
// that is on the right-hand-side of current row of x...
while (x.RHE().marker_next());
}
while (x.marker_next());

For small projects, I guess it would not too muchmatter, but I just
did a grep on 'List<' in my project, and got 1560 hits, excluding
comments, so I cannot imagine declaring all those iterators just to
iterator over containers.

-Chaud Lapin-

Le Chaud Lapin

не прочитано,
5 авг. 2003 г., 03:29:0005.08.2003
al...@start.no (Alf P. Steinbach) wrote in message news:<3f2d42d5....@News.CIS.DFN.DE>...
> On 2 Aug 2003 22:07:43 -0400, unorigina...@yahoo.com (Le Chaud Lapin)
> >Unlike STL, I kept an iterator internal to my List<> class and let
> >functions move it around to access elements of the list as necessary:
> >
> >list.marker_home(); // puts iterator (marker) at beginning of list.
> >
> >Keeping the marker internal turns out to be very convenient,
>
> How?

It is conceptual. I would much rather think of a container as a
bucket, possibly empty, that has a cursor in it that jumps around when
you shake it. I never have to worry about creating an iterator value
for ad-hoc looping operations because the container always has one. I
never have to worry about the iterator becoming invalid - that's
impossible. If it is necessary to give siginificance to the state of
the iterator, I do that:

unsigned int i = marker_index();
foo (list); // foo moves internal marker
list.seek (i);

I chose to do it this way because it seemed that, in the vast majority
of cases, the iterator is used for simply iterating without
significance given to its inter-call position (used like an int in a
for loop).

Given this, and knowing that I would have many (right now more than
25) global containers in my project, I decided to let the iterator
stay with container as a unit. It keeps down number of globabl
variables, and it keeps down on clutter in code.

>>elements should always be permissible.
>
> IMO that is abuse of 'mutable'.
>

Perhaps. Maybe I should have casted-away const insided my List<>
marker-movement member functions and not used 'mutable' at all.

-Chaud Lapin-

Hyman Rosen

не прочитано,
5 авг. 2003 г., 03:30:3305.08.2003
Le Chaud Lapin wrote:
> For small projects, I guess it would not too muchmatter, but I just
> did a grep on 'List<' in my project, and got 1560 hits, excluding
> comments, so I cannot imagine declaring all those iterators just to
> iterator over containers.

Why in the world aren't you using typedefs? This whole thing is a
complete red herring.

> Associative_List<String, List<Associative_List<Digital_Address,
> Cipher_Rijndael::Key> > > x;

typedef std::map<Digital_Address, Cipher_Rijndael::Key> t_key_of_addr;
typedef std::list<t_key_of_addr> t_keys;
typedef std::map<std::string, t_keys> t_keys_of_name;
t_keys_of_name x;
t_keys_of_name::iterator b = x.begin(), e = x.end();

Le Chaud Lapin

не прочитано,
6 авг. 2003 г., 20:50:0706.08.2003
Hyman Rosen <hyr...@mail.com> wrote in message news:<3tCXa.7595$mZ6....@nwrdny02.gnilink.net>...

> Le Chaud Lapin wrote:
> > For small projects, I guess it would not too muchmatter, but I just
> > did a grep on 'List<' in my project, and got 1560 hits, excluding
> > comments, so I cannot imagine declaring all those iterators just to
> > iterator over containers.
>
> Why in the world aren't you using typedefs? This whole thing is a
> complete red herring.
>
> > Associative_List<String, List<Associative_List<Digital_Address,
> > Cipher_Rijndael::Key> > > x;
>
> typedef std::map<Digital_Address, Cipher_Rijndael::Key> t_key_of_addr;
> typedef std::list<t_key_of_addr> t_keys;
> typedef std::map<std::string, t_keys> t_keys_of_name;
> t_keys_of_name x;
> t_keys_of_name::iterator b = x.begin(), e = x.end();
>

The STL container model notwithstanding, this use of typedef is
superflous, and in terms of allowing me to visualize my system, it
actually interferes more than it helps.

-Chaud Lapin-

Oleg Goldshmidt

не прочитано,
10 авг. 2003 г., 20:11:3010.08.2003
yu...@tsoft.com (Yuri Victorovich) writes:

> My question is: can anyone provide an example when mutable will fit
> into nice and logical design of objects ?
>
> I think it's in the language just to enable certain ways of hacking
> of existing code.
> > My rationale: if it's the concept of const objects that's what
> > this means: constant.
> Why to ever open the back door and allow to change field marked as
> "mutable" ?


It is used to distinguish between conceptually immutable and bitwise
immutable objects. Think of a const member function: is it allowed to
modify some bits in the object it is invoked on? The answer is, if it
is undetectable by clients, it may do so.

The classic example is cacheing, e.g. imagine a String class with a
length member function that caches the length in a data field. It
should be allowed to do so even when invoked on const String. This is
achieved by making the private cached_length field mutable. For all
client code this will be undetectable, and the conceptual immutability
will be preserved.

--
Oleg Goldshmidt | p...@NOSPAM.goldshmidt.org

Ответить всем
Написать сообщение автору
Переслать
0 новых сообщений