Topic: STL-Related Thread Question
Author: scorp@btinternet.com (Dave Harris)
Date: 2000/01/03 Raw View
kanze@gabi-soft.de () wrote:
> Don't you think it strange that the semantics of operator[] for a map
> are significantly different than those of an array?
Absolutely, yes.
> What's wrong with:
>
> while ( logfile.nextline() ) {
> (*userHits.insert( logfile.username() )) ++ ;
> }
>
Does that work as std::map is currently defined? I thought
std::map<>::insert() returned a pair<iterator,bool> so I would expect to
need a "first" to get at an iterator, and *iterator will also be a pair so
I would expect to need a "second" to get at the thing you want to
increment. I thought the resulting expression is what Bill Klein described
as "not pretty", and what we wanted to improve upon.
If you mean, take my "add", rename it to "insert" and return a pointer
instead of a reference, than OK, although I don't see much improvement. My
personal convention is to use "add" for unordered collections and "insert"
and "append" for specific positions in ordered collections (defaulting to
front and back).
> In fact, we really do need two functions, depending on the desired
> behavior when the key isn't present. And I don't like the name insert
> for either, but I really don't have any good suggestions either.
We're in agreement, then.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: a.robbie@altavista.net (Andrew J Robbie)
Date: 2000/01/03 Raw View
In article <386fbf9a.57468405@news.videotron.ca>, bill@orbit.org (Bill
Klein) wrote:
> Just wanted to point out that you are using std::find
> when you should be using map::find, but that doesn't
> change anything...
Sorry about that, it just slipped in there...
> I also don't understand your argument
> about why you would prefer an exception to be thrown
> when accessing an out-of-bounds element using [] rather
> than using find() and checking the result.
I guess that I am arguing that there should be different
interfaces available depending upon whether you are fairly
sure what you are searching for is in the map versus if you
have no particular expectation either way. But as it is
you really have to use find() for both cases, and op[] is
really just a glorified insertion mechanism. If you try to
use op[] just to access the mapping you are doing the
wrong thing, which is totally counter-intuitive, especially
in the context of other STL syntax, eg vector's op[] -- if
vector took the same approach as map, accessing past the
end of the array would expand the array.
> What do you
> do with std::list and all the others? For that matter,
> what do you do with vector whose behavior is undefined
> if you access an element out of bounds with [] (have to
> use at()).
Strictly speaking, yes, it should not be map::op[] that
throws an out of bounds error but some other function. But
I don't think that using a throwing op[] would seem strange
to most programmers -- especially when it doesn't cost any
more to have such 'bounds checking'. (Actually, it would be
nice if there was a #def you could set which would turn on
bounds checking for vectors during testing; or a similar
container, eg <bcvector> which you could swap in easily,
rather than using at() which is permanently slower.)
> std::map<string,int> usersHits;
>
> while( logfile.nextline() )
> {
> userHits[ logfile.username() ]++;
> }
>
> That was pretty easy. Try writing this without operator[]
> as it currently is. It's not hard, but it's also not
> pretty...
You mean like this?
string username = logfile.username();
map<string,int> find_it = userHits.find(username);
if (find_it != userHits.end())
(*find_it)++;
else
userHits.insert(map<string, int>::value_type(username, 0));
> I understand your basic argument too and agree that op []
> in map doesn't work exactly as one would expect at first.
> But I also see that it's useful the way it is defined now
> and if you don't like it you have alternatives (find(),
> insert(), etc.) that do what you might have hoped for...
No doubt op[] was designed with code like your example in mind
(ie building a map from external data); I still think think it
runs counter to the way one would expect with no good reason,
and contradicts the style of other parts of the STL too.
Regards,
Andrew
--
a.robbie (at) altavista.net
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: kanze@gabi-soft.de
Date: 2000/01/03 Raw View
scorp@btinternet.com (Dave Harris) writes:
|> kanze@gabi-soft.de () wrote:
|> > Don't you think it strange that the semantics of operator[] for a map
|> > are significantly different than those of an array?
|> Absolutely, yes.
|> > What's wrong with:
|> > while ( logfile.nextline() ) {
|> > (*userHits.insert( logfile.username() )) ++ ;
|> > }
|> Does that work as std::map is currently defined? I thought
|> std::map<>::insert() returned a pair<iterator,bool> so I would
|> expect to need a "first" to get at an iterator, and *iterator will
|> also be a pair so I would expect to need a "second" to get at the
|> thing you want to increment.
Correct. I was influenced by my own AssocArray classes, and was typing
late at night.
|> I thought the resulting expression is
|> what Bill Klein described as "not pretty", and what we wanted to
|> improve upon.
Well, I find almost any use of STL results in things that are "not
pretty". STL was designed for a maximum of flexibility and speed, which
doesn't always lead to the simplest use. (STL is the first time I've
seen a map class without a "contains" method, for example.)
|> If you mean, take my "add", rename it to "insert" and return a
|> pointer instead of a reference, than OK, although I don't see much
|> improvement. My personal convention is to use "add" for unordered
|> collections and "insert" and "append" for specific positions in
|> ordered collections (defaulting to front and back).
Sounds like a reasonable convention. (Of course, after having used
Java, with its alternances between add, put and putValue, *any*
convention would seem reasonable.) I've generally used insert for
everything, with insertAtFront, insertAtBack, insertAfter( Iterator )
and insertBefore( Iterator ) for ordered collections.
What I don't like, whether the name is add or insert, is the fact that
sometimes (most of the time?) it doesn't. It's more an
readAndCreateIfNecessary function, but that name is a little too long
even for me.
--
James Kanze mailto:James.Kanze@gabi-soft.de
Conseils en informatique orient e objet/
Beratung in Objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: kanze@gabi-soft.de
Date: 2000/01/05 Raw View
a.robbie@altavista.net (Andrew J Robbie) writes:
|> I guess that I am arguing that there should be different
|> interfaces available depending upon whether you are fairly
|> sure what you are searching for is in the map versus if you
|> have no particular expectation either way. But as it is
|> you really have to use find() for both cases, and op[] is
|> really just a glorified insertion mechanism.
Is operator[] a glorified insertion mechanism, or is insert a somewhat
particular access function. According to the application, having
implicit creation of the elements is either good or bad. I prefer
having two separate functions, one which implicitly creates, and one
which doesn't. And no operator[], because it is not evident which
function it should map to (although after so many years of AWK, one
seems more natural to me than the other).
|> If you try to
|> use op[] just to access the mapping you are doing the
|> wrong thing, which is totally counter-intuitive, especially
|> in the context of other STL syntax, eg vector's op[] -- if
|> vector took the same approach as map, accessing past the
|> end of the array would expand the array.
One of my array classes did just that.
|> > What do you
|> > do with std::list and all the others? For that matter,
|> > what do you do with vector whose behavior is undefined
|> > if you access an element out of bounds with [] (have to
|> > use at()).
|> Strictly speaking, yes, it should not be map::op[] that
|> throws an out of bounds error but some other function. But
|> I don't think that using a throwing op[] would seem strange
|> to most programmers -- especially when it doesn't cost any
|> more to have such 'bounds checking'. (Actually, it would be
|> nice if there was a #def you could set which would turn on
|> bounds checking for vectors during testing; or a similar
|> container, eg <bcvector> which you could swap in easily,
|> rather than using at() which is permanently slower.)
Operator[] may do bounds checking on a vector. Some implementations do.
It would be nice if templates really worked, and you could make the
switch just by linking against a different library.
|> > std::map<string,int> usersHits;
|> > while( logfile.nextline() )
|> > {
|> > userHits[ logfile.username() ]++;
|> > }
|> > That was pretty easy. Try writing this without operator[]
|> > as it currently is. It's not hard, but it's also not
|> > pretty...
|> You mean like this?
|>
|> string username = logfile.username();
|> map<string,int> find_it = userHits.find(username);
|>
|> if (find_it != userHits.end())
|> (*find_it)++;
|> else
|> userHits.insert(map<string, int>::value_type(username, 0));
|> > I understand your basic argument too and agree that op []
|> > in map doesn't work exactly as one would expect at first.
|> > But I also see that it's useful the way it is defined now
|> > and if you don't like it you have alternatives (find(),
|> > insert(), etc.) that do what you might have hoped for...
|> No doubt op[] was designed with code like your example in mind
|> (ie building a map from external data); I still think think it
|> runs counter to the way one would expect with no good reason,
|> and contradicts the style of other parts of the STL too.
Perhaps it was designed with the behavior of Unix programs like AWK in
mind.
--
James Kanze mailto:James.Kanze@gabi-soft.de
Conseils en informatique orientie objet/
Beratung in Objekt orientierter Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: a.robbie@altavista.net (Andrew J Robbie)
Date: 1999/12/26 Raw View
In article <hinnant-2509991419220001@ith3-103.twcny.rr.com>,
hinnant@anti-spam_metrowerks.com (Howard Hinnant) wrote:
> In article <7simmc$lck$1@news03.btx.dtag.de>, "bragason"
> <bragason@hotmail.com> wrote:
> >
> > std::map<int, std::queue<T> >
[snippage]
> As a practical matter I suspect that most modern implementations will be
> ok with the scenario you describe IF the index operation into m does not
> create a queue.
But since there is no guarentee of this being the case you should add some
heavy commenting about your assumptions. It is not inconceivable that later
on the mapping container will be changed (in the library), or that another
type of container will be used (eg some sort of hash map). So it might be
a good idea to wrap it up in some accessor functions which can handle
threading, and know which operations invalidate iterators. Then use the
multiple-readers, single writer locks (not sure if you can do this easily
with Win32 threads though).
> The operator[] on map is a non-const operation, and generally speaking,
> two threads executing a non-const op on the same object at the same time
> is a Bad Thing. But op[] is special in that it only modifies the map if
> the key,value pair does not yet exist in the map.
This 'feature' has been the cause of so much extra code; why oh why was
it written like this? If only it threw an exception when it couldn't find
the key, instead of inserting. Or perhaps another function could be added
which would behave this way, say, operator().
> If you can garauntee
> that your tree is fully constructed (all queues in place) before multiple
> threads start pushing and poping on it, then I think you're ok.
Yes, and access the map as a const object.
[ Q: But wait -- doesn't the fact that op[] is non-const prevent that?
A: Why, yes it does. Drat.
Q: And if I have a map as a private member variable of an object that
is const, won't that stop the const member functions from using the
map?
Q: Yes -- but don't worry, that is what 'mutable' is for. ]
Happy new year,
Andrew
--
a.robbie (at) altavista.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: bill@orbit.org (Bill Klein)
Date: 1999/12/27 Raw View
>> The operator[] on map is a non-const operation, and generally speaking,
>> two threads executing a non-const op on the same object at the same time
>> is a Bad Thing. But op[] is special in that it only modifies the map if
>> the key,value pair does not yet exist in the map.
a.robbie@altavista.net (Andrew J Robbie) wrote:
>This 'feature' has been the cause of so much extra code; why oh why was
>it written like this? If only it threw an exception when it couldn't find
>the key, instead of inserting. Or perhaps another function could be added
>which would behave this way, say, operator().
I personally find it very useful the way operator[] work
in certain situations. In other situations, where it's
not so useful, why not just use map::find() ?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: a.robbie@altavista.net (Andrew J Robbie)
Date: 1999/12/30 Raw View
In article <386780e8.1222343747@news.videotron.ca>, bill@orbit.org (Bill
Klein) wrote:
> >> The operator[] on map is a non-const operation, and generally speaking,
> >> two threads executing a non-const op on the same object at the same time
> >> is a Bad Thing. But op[] is special in that it only modifies the map if
> >> the key,value pair does not yet exist in the map.
>
> a.robbie@altavista.net (Andrew J Robbie) wrote:
> >This 'feature' has been the cause of so much extra code; why oh why was
> >it written like this? If only it threw an exception when it couldn't find
> >the key, instead of inserting. Or perhaps another function could be added
> >which would behave this way, say, operator().
>
> I personally find it very useful the way operator[] work
> in certain situations. In other situations, where it's
> not so useful, why not just use map::find() ?
I guess I might be being a bit picky about this, but it seems wrong from
an aesthetic perspective. For example, if you do `ls foo`, and foo is not
present, would you expect ls to create a zero length file called 'foo' ?
Does SQL insert a record for a search key when the result is empty?
Apart from that, it obscures the intent of the code by cluttering it with
error (pre-)processing, or forces you to write an auxilliary function. IE,
instead of writing
try {
string karens_number = whitePages[string("Karen");
ring(karens_number); // Ring karen ...
}
catch (out_of_range_exception e) {
cerr << ...
}
we write
map<string, string>::const_iterator pos_it;
pos_it = find(whitePages.begin(), whitePages.end(), "Karen");
if (pos_it != whitePages.end()) {
// ring(*pos_it);
}
else {
cerr << ...
cerr << "op[] would have inserted an entry for Karen"
<< " with a blank telephone number."
}
Admittedly my example might not be the best, but my point is that if we
have to use an iterator to search for the entry, why bother having a
special operator[]. If you don't mind having things inserted willy-nilly,
fine, but I think from a debugging perspective it would be nice to know
when things like that happen. Also, if you want to query whether you have
Karen's telephone number it is a pain to have to do a strlen (or other
internal metric, if that type has a zero) to determine whether you *really*
have the number, or just that a previous search inserted an entry for her
name.
Finally, as the (snipped) sarcastic comment in my previous article mentioned,
it does mayhem to strategies of const-correctness, and leads to the misuse
of features like 'mutable'; const seems to erode rather too easily, no doubt
why we hear occasional calls for 'const by default' or moding of function
arguments (the latter, IMHO, would be a boon in many respects).
So, can any of the gurus of the standards process reveal why/how the current
mechanism was chosen, or, optionally, find gaping holes in my reasoning?
Regards,
Andrew
--
Save the whales! Protect the pandas! Free the Mallocs!
a.robbie (at) altavista.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: bill@orbit.org (Bill Klein)
Date: 1999/12/31 Raw View
a.robbie@altavista.net (Andrew J Robbie) wrote:
>Apart from that, it obscures the intent of the code by cluttering it with
>error (pre-)processing, or forces you to write an auxilliary function. IE,
>instead of writing
>
> <example snipped>
Just wanted to point out that you are using std::find
when you should be using map::find, but that doesn't
change anything... I also don't understand your argument
about why you would prefer an exception to be thrown
when accessing an out-of-bounds element using [] rather
than using find() and checking the result. What do you
do with std::list and all the others? For that matter,
what do you do with vector whose behavior is undefined
if you access an element out of bounds with [] (have to
use at()).
I'd certainly understand your argument if [] is all that
was provided for map and it worked the way it did, but
seeing as it's just an alternative, I don't see the
problem...
>Admittedly my example might not be the best, but my point is that if we
>have to use an iterator to search for the entry, why bother having a
>special operator[]. If you don't mind having things inserted willy-nilly,
>fine, but I think from a debugging perspective it would be nice to know
>when things like that happen.
Maybe the reason why I see the operator [] being useful
the way it is, is because I'm used to the way the Perl
hash table works and I see the map as having the same
type of uses. Here's a small example of some code that
is made simpler by the way it works as-is. It goes through
a log file for a web site and finishes with having a list
of users that have accessed the site in addition to the
number of hits by each (the number of occurrences in the
log file for that user):
std::map<string,int> usersHits;
while( logfile.nextline() )
{
userHits[ logfile.username() ]++;
}
That was pretty easy. Try writing this without operator[]
as it currently is. It's not hard, but it's also not
pretty...
> .......Also, if you want to query whether you have
>Karen's telephone number it is a pain to have to do a strlen (or other
>internal metric, if that type has a zero) to determine whether you *really*
>have the number, or just that a previous search inserted an entry for her
>name.
I'm sorry but that's not a valid argument. You're thinking
that you use operator [] to do a search for an element but
that's simply not true. You use it to do things like I
show above. You use (!) map::find() to search for an element.
>Finally, as the (snipped) sarcastic comment in my previous article mentioned,
>it does mayhem to strategies of const-correctness, and leads to the misuse
>of features like 'mutable'; const seems to erode rather too easily, no doubt
>why we hear occasional calls for 'const by default' or moding of function
>arguments (the latter, IMHO, would be a boon in many respects).
Again I think you're missing it in the same way as above.
You wouldn't use operator [] in a const context *because*
it's meant to be used to modify the map (either by inserting
an element or simply by accessing an existing element for
modification). So the fact that you can't use it in const
context makes sense and is a good thing.
>So, can any of the gurus of the standards process reveal why/how the current
>mechanism was chosen, or, optionally, find gaping holes in my reasoning?
Just to clear things up, I'm not even slightly a guru in
any respect whatsoever. I'm just saying it as I see it.
I understand your basic argument too and agree that op []
in map doesn't work exactly as one would expect at first.
But I also see that it's useful the way it is defined now
and if you don't like it you have alternatives (find(),
insert(), etc.) that do what you might have hoped for...
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: scorp@btinternet.com (Dave Harris)
Date: 2000/01/01 Raw View
bill@orbit.org (Bill Klein) wrote:
> I also don't understand your argument about why you would prefer
> an exception to be thrown when accessing an out-of-bounds element
> using [] rather than using find() and checking the result. What do
> you do with std::list and all the others? For that matter, what do
> you do with vector whose behavior is undefined if you access an
> element out of bounds with [] (have to use at()).
Don't you think it strange that a const array or a const vector has
operator[], but a const map doesn't? There's quite an inconsistency here.
> That was pretty easy. Try writing this without operator[]
> as it currently is. It's not hard, but it's also not
> pretty...
The functionality of std::map::operator[] is jolly useful. However, is it
best suited to that name? If we had, say, add() with the same
functionality your code could be written as:
while (logfile.nextline())
userHits.add( logfile.username() )++;
In my view, this is clearer than using operator[]. There may be a better
name than "add". Whatever, it should imply that the map may be changed and
the new item is not inserted at any well-defined position.
Removing operator[] entirely was not the only design option. I think there
is a whiff of the "excluded middle" fallacy in your argument.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 2000/01/02 Raw View
On 1 Jan 2000 21:50:54 GMT, scorp@btinternet.com (Dave Harris) wrote:
: Don't you think it strange that a const array or a const vector has
: operator[], but a const map doesn't? There's quite an inconsistency here.
Alternatively, a const map is an inconsistency, in fact, an oxymoron. A
map is, was, and always will be an associative array which never has an
invalid subscript.
: The functionality of std::map::operator[] is jolly useful. However, is it
: best suited to that name?
It has always had that name. Nawk added contains to make the
associative array searchable, map has count.
I wish someone would define the interface of some non-existent
container that they desire and quit trying to break set and map.
I think the desire is an ordered container of records with add,
change, delete, find. Neither set nor map is that container.
Either can be bent, buckled and distorted to do the job, but
they each already do their intended job well.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: kanze@gabi-soft.de
Date: 2000/01/02 Raw View
scorp@btinternet.com (Dave Harris) writes:
|> bill@orbit.org (Bill Klein) wrote:
|> > I also don't understand your argument about why you would prefer
|> > an exception to be thrown when accessing an out-of-bounds element
|> > using [] rather than using find() and checking the result. What do
|> > you do with std::list and all the others? For that matter, what do
|> > you do with vector whose behavior is undefined if you access an
|> > element out of bounds with [] (have to use at()).
|> Don't you think it strange that a const array or a const vector has
|> operator[], but a const map doesn't? There's quite an inconsistency here.
It depends. Don't you think it strange that the semantics of operator[]
for a map are significantly different than those of an array?
|> > That was pretty easy. Try writing this without operator[]
|> > as it currently is. It's not hard, but it's also not
|> > pretty...
|> The functionality of std::map::operator[] is jolly useful. However, is it
|> best suited to that name? If we had, say, add() with the same
|> functionality your code could be written as:
|> while (logfile.nextline())
|> userHits.add( logfile.username() )++;
|> In my view, this is clearer than using operator[]. There may be a
|> better name than "add". Whatever, it should imply that the map may
|> be changed and the new item is not inserted at any well-defined
|> position.
What's wrong with:
while ( logfile.nextline() ) {
(*userHits.insert( logfile.username() )) ++ ;
}
In fact, the desired semantics depend on the application, and I know
people who complained loudly over the automatic insertion in the USL map
classes.
In fact, we really do need two functions, depending on the desired
behavior when the key isn't present. And I don't like the name insert
for either, but I really don't have any good suggestions either.
|> Removing operator[] entirely was not the only design option. I think
|> there is a whiff of the "excluded middle" fallacy in your argument.
--
James Kanze mailto:James.Kanze@gabi-soft.de
Conseils en informatique orient e objet/
Beratung in Objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1999/10/01 Raw View
> Howard Hinnant wrote:
>
> > In article <7simmc$lck$1@news03.btx.dtag.de>, "bragason"
> > <bragason@hotmail.com> wrote:
> >
> > > Consider an object of the following class:
> > >
> > > std::map<int, std::queue<T> >
> > >
> > > That is, an object m is a map of queues of T objects, indexed by an
> > > integer, so m[3], say, is a queue of T objects. Now, many threads want to
> > > access the queues, e.g. with m[3].push(T t) and m[5].pop(). I use mutexes to
> > > make sure that a _single_ queue within the map is not pushed and/or popped
> > > by two threads simultaneously, which leads to my main question: could the
> > > "simultaneous" modification (push() and/or pop()) of two _different_ queues,
> > > m[2] and m[3], say, lead to some sort of "lost update" situation (remember,
> > > m is a single object!).
Boris Fomitchev <fbp@stlport.org> wrote in message
news:37F28847.77E9B1A8@stlport.org...
>
> Your question is not being addressed by the standard, as it says nothing
> about threads. You should examine if the implementation you are using
> is thread-safe. To my knowledge, latest implementations from major
> vendors like Microsoft and SUN are safe in this regard, as well as
> SGI STL and STLport. If you use old MS one, you might be in trouble,
though.
The only way one thread operating on one queue in a map could interfere with
another thread operating on another queue in the same map (or anywhere else
in the program) is if the queue template used some global variable
internally. There's no need for queues to do that, and any implementation
that did that would have to be regarded as pathological.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Boris Fomitchev <fbp@stlport.org>
Date: 1999/09/30 Raw View
Your question is not being addressed by the standard, as it says nothing
about threads. You should examine if the implementation you are using
is thread-safe. To my knowledge, latest implementations from major
vendors like Microsoft and SUN are safe in this regard, as well as
SGI STL and STLport. If you use old MS one, you might be in trouble, though.
-Boris.
Howard Hinnant wrote:
> In article <7simmc$lck$1@news03.btx.dtag.de>, "bragason"
> <bragason@hotmail.com> wrote:
>
> > Hello.
> > I am working on a project where I use the Standard Template Library as well
> > as multiple threads. As I am a little bit worried about my implemenation, I
> > ask you to consider the following: (The project is developed on Win32,
> > although I personally prefer Linux and pthreads.)
> > Consider an object of the following class:
> >
> > std::map<int, std::queue<T> >
> >
> > That is, an object m is a map of queues of T objects, indexed by an
> > integer, so m[3], say, is a queue of T objects. Now, many threads want to
> > access the queues, e.g. with m[3].push(T t) and m[5].pop(). I use mutexes to
> > make sure that a _single_ queue within the map is not pushed and/or popped
> > by two threads simultaneously, which leads to my main question: could the
> > "simultaneous" modification (push() and/or pop()) of two _different_ queues,
> > m[2] and m[3], say, lead to some sort of "lost update" situation (remember,
> > m is a single object!).
> > I would greatly appreciate if anyone could comment on the safety or
> > non-safety of this approach. Thanks!
>
> As far as the standard is concerned, ... well, the standard says nothing
> about this situation. So the answer to your question is completely
> implementation dependent.
>
> As a practical matter I suspect that most modern implementations will be
> ok with the scenario you describe IF the index operation into m does not
> create a queue.
>
> The operator[] on map is a non-const operation, and generally speaking,
> two threads executing a non-const op on the same object at the same time
> is a Bad Thing. But op[] is special in that it only modifies the map if
> the key,value pair does not yet exist in the map. If you can garauntee
> that your tree is fully constructed (all queues in place) before multiple
> threads start pushing and poping on it, then I think you're ok. If you
> have multiple threads accessing the map while key,value pairs are still
> being created, then I would think you need to mutex the map as well. But
> better check with your vendor to be sure!
>
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: hinnant@anti-spam_metrowerks.com (Howard Hinnant)
Date: 1999/09/27 Raw View
In article <7simmc$lck$1@news03.btx.dtag.de>, "bragason"
<bragason@hotmail.com> wrote:
> Hello.
> I am working on a project where I use the Standard Template Library as well
> as multiple threads. As I am a little bit worried about my implemenation, I
> ask you to consider the following: (The project is developed on Win32,
> although I personally prefer Linux and pthreads.)
> Consider an object of the following class:
>
> std::map<int, std::queue<T> >
>
> That is, an object m is a map of queues of T objects, indexed by an
> integer, so m[3], say, is a queue of T objects. Now, many threads want to
> access the queues, e.g. with m[3].push(T t) and m[5].pop(). I use mutexes to
> make sure that a _single_ queue within the map is not pushed and/or popped
> by two threads simultaneously, which leads to my main question: could the
> "simultaneous" modification (push() and/or pop()) of two _different_ queues,
> m[2] and m[3], say, lead to some sort of "lost update" situation (remember,
> m is a single object!).
> I would greatly appreciate if anyone could comment on the safety or
> non-safety of this approach. Thanks!
As far as the standard is concerned, ... well, the standard says nothing
about this situation. So the answer to your question is completely
implementation dependent.
As a practical matter I suspect that most modern implementations will be
ok with the scenario you describe IF the index operation into m does not
create a queue.
The operator[] on map is a non-const operation, and generally speaking,
two threads executing a non-const op on the same object at the same time
is a Bad Thing. But op[] is special in that it only modifies the map if
the key,value pair does not yet exist in the map. If you can garauntee
that your tree is fully constructed (all queues in place) before multiple
threads start pushing and poping on it, then I think you're ok. If you
have multiple threads accessing the map while key,value pairs are still
being created, then I would think you need to mutex the map as well. But
better check with your vendor to be sure!
-Howard
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "bragason" <bragason@hotmail.com>
Date: 1999/09/25 Raw View
Hello.
I am working on a project where I use the Standard Template Library as well
as multiple threads. As I am a little bit worried about my implemenation, I
ask you to consider the following: (The project is developed on Win32,
although I personally prefer Linux and pthreads.)
Consider an object of the following class:
std::map<int, std::queue<T> >
That is, an object m is a map of queues of T objects, indexed by an
integer, so m[3], say, is a queue of T objects. Now, many threads want to
access the queues, e.g. with m[3].push(T t) and m[5].pop(). I use mutexes to
make sure that a _single_ queue within the map is not pushed and/or popped
by two threads simultaneously, which leads to my main question: could the
"simultaneous" modification (push() and/or pop()) of two _different_ queues,
m[2] and m[3], say, lead to some sort of "lost update" situation (remember,
m is a single object!).
I would greatly appreciate if anyone could comment on the safety or
non-safety of this approach. Thanks!
David Bragason, Germany.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]