public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* c++ std::map problem
@ 2003-08-26 14:03 Martin Voelkle
  2003-08-26 15:02 ` Tony Wetmore
  0 siblings, 1 reply; 3+ messages in thread
From: Martin Voelkle @ 2003-08-26 14:03 UTC (permalink / raw)
  To: gcc-help

[-- Attachment #1: Type: text/plain, Size: 708 bytes --]

Hello,

please cc me.

I'm having trouble making this snip of code work. I just want to keep a 
map of created objects (for (un)marshalling), but when I run the 
attached code, I see that the constructor is only called once, giving an 
output of 0111.

Now if I make this change:
-    static const toto* create() { return &totos[nextid]; }
+    static const toto* create() { toto(); return &totos[nextid]; }
I get 0246, which is what is expected, but not the initial objective.

Am I doing something wrong? Is there a bug in g++ or libstdc++?
I get the problem with both 3.3.2 20030812 and 2.95.4 20011002 (Debian sid)
I don't know what kind of keywords I could use to search, so I have to post.

Thank you,

[-- Attachment #2: toto.cpp --]
[-- Type: text/x-c++src, Size: 615 bytes --]

#include <iostream>
#include <map>

class toto {
	toto():id(nextid++){}
	const unsigned int id;
	friend class std::map<unsigned int, const toto>;
public: // for debug purposes
	static std::map<unsigned int, const toto> totos;
	static unsigned int nextid;
public:
	static const toto* create() { return &totos[nextid]; }
};

unsigned int toto::nextid(0);
std::map<unsigned int, const toto> toto::totos;

int main(int argc, char* argv[]) {
	std::cout << toto::nextid;
	toto::create();
	std::cout << toto::nextid;
	toto::create();
	std::cout << toto::nextid;
	toto::create();
	std::cout << toto::nextid << std::endl;
}

^ permalink raw reply	[flat|nested] 3+ messages in thread

* RE: c++ std::map problem
  2003-08-26 14:03 c++ std::map problem Martin Voelkle
@ 2003-08-26 15:02 ` Tony Wetmore
  2003-08-26 15:16   ` Martin Voelkle
  0 siblings, 1 reply; 3+ messages in thread
From: Tony Wetmore @ 2003-08-26 15:02 UTC (permalink / raw)
  To: 'Martin Voelkle', gcc-help

The "problem" here appears to be that the first element is actually
inserted with a key value of 1, rather than 0.  This happens because the
key parameter passed to std::map<>::operator[] is passed by reference,
rather than by value (const key_type& __k).

So, when you insert the first element into your map, the object is
constructed, then nextid is incremented to 1.  After this is done, the
element is inserted, with a key value of 1, rather than 0.

On the subsequent operator[] calls, nextid is set to 1, so it looks for
an entry with a key of 1, and finds the first object that was created.

Adding the additional call to the toto constructor increments the nextid
by one, which causes the code to "work", although the objects are still
inserted with the "wrong" (I believe) key value.  That is, of course,
assuming that in this code the key value should match the "id" of the
toto object.

If you print out the contents of the map after each call to
toto::create(), you'll see the effect that I'm talking about.

So this does not appear to be a bug in the C++ library, but rather an
unfortunate side effect of the fact that the key type is passed by
reference, rather than by value.  And since, in your case, that key
object changes value "midway" through the insertion, you get bad
behavior.

To fix the problem, you could store the current value of nextid in a
temporary within toto::create() and use that in the map indexing
operation instead:

   static const toto* create() { unsigned int n = nextid; return
&totos[n]; }

That causes the map to be created with key values that match the "id" of
each object in the map, verified by printing out the map after each call
to toto::create().

---
Tony Wetmore
Raytheon Solipsys
mailto:tony.wetmore@solipsys.com
http://www.solipsys.com
 
 


-----Original Message-----
From: gcc-help-owner@gcc.gnu.org [mailto:gcc-help-owner@gcc.gnu.org] On
Behalf Of Martin Voelkle
Sent: Tuesday, August 26, 2003 10:03 AM
To: gcc-help@gcc.gnu.org
Subject: c++ std::map problem


Hello,

please cc me.

I'm having trouble making this snip of code work. I just want to keep a 
map of created objects (for (un)marshalling), but when I run the 
attached code, I see that the constructor is only called once, giving an

output of 0111.

Now if I make this change:
-    static const toto* create() { return &totos[nextid]; }
+    static const toto* create() { toto(); return &totos[nextid]; }
I get 0246, which is what is expected, but not the initial objective.

Am I doing something wrong? Is there a bug in g++ or libstdc++? I get
the problem with both 3.3.2 20030812 and 2.95.4 20011002 (Debian sid) I
don't know what kind of keywords I could use to search, so I have to
post.

Thank you,

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: c++ std::map problem
  2003-08-26 15:02 ` Tony Wetmore
@ 2003-08-26 15:16   ` Martin Voelkle
  0 siblings, 0 replies; 3+ messages in thread
From: Martin Voelkle @ 2003-08-26 15:16 UTC (permalink / raw)
  To: Tony Wetmore; +Cc: gcc-help

Damn you're good!
Thank you, it now works exacly as I wanted.
I should have checked the contents of the map before asking.
Martin

Tony Wetmore wrote:

>The "problem" here appears to be that the first element is actually
>inserted with a key value of 1, rather than 0.  This happens because the
>key parameter passed to std::map<>::operator[] is passed by reference,
>rather than by value (const key_type& __k).
>
>So, when you insert the first element into your map, the object is
>constructed, then nextid is incremented to 1.  After this is done, the
>element is inserted, with a key value of 1, rather than 0.
>
>On the subsequent operator[] calls, nextid is set to 1, so it looks for
>an entry with a key of 1, and finds the first object that was created.
>
>Adding the additional call to the toto constructor increments the nextid
>by one, which causes the code to "work", although the objects are still
>inserted with the "wrong" (I believe) key value.  That is, of course,
>assuming that in this code the key value should match the "id" of the
>toto object.
>
>If you print out the contents of the map after each call to
>toto::create(), you'll see the effect that I'm talking about.
>
>So this does not appear to be a bug in the C++ library, but rather an
>unfortunate side effect of the fact that the key type is passed by
>reference, rather than by value.  And since, in your case, that key
>object changes value "midway" through the insertion, you get bad
>behavior.
>
>To fix the problem, you could store the current value of nextid in a
>temporary within toto::create() and use that in the map indexing
>operation instead:
>
>   static const toto* create() { unsigned int n = nextid; return
>&totos[n]; }
>
>That causes the map to be created with key values that match the "id" of
>each object in the map, verified by printing out the map after each call
>to toto::create().
>
>---
>Tony Wetmore
>Raytheon Solipsys
>mailto:tony.wetmore@solipsys.com
>http://www.solipsys.com
> 
> 
>
>
>-----Original Message-----
>From: gcc-help-owner@gcc.gnu.org [mailto:gcc-help-owner@gcc.gnu.org] On
>Behalf Of Martin Voelkle
>Sent: Tuesday, August 26, 2003 10:03 AM
>To: gcc-help@gcc.gnu.org
>Subject: c++ std::map problem
>
>
>Hello,
>
>please cc me.
>
>I'm having trouble making this snip of code work. I just want to keep a 
>map of created objects (for (un)marshalling), but when I run the 
>attached code, I see that the constructor is only called once, giving an
>
>output of 0111.
>
>Now if I make this change:
>-    static const toto* create() { return &totos[nextid]; }
>+    static const toto* create() { toto(); return &totos[nextid]; }
>I get 0246, which is what is expected, but not the initial objective.
>
>Am I doing something wrong? Is there a bug in g++ or libstdc++? I get
>the problem with both 3.3.2 20030812 and 2.95.4 20011002 (Debian sid) I
>don't know what kind of keywords I could use to search, so I have to
>post.
>
>Thank you,
>
>  
>


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2003-08-26 15:16 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-08-26 14:03 c++ std::map problem Martin Voelkle
2003-08-26 15:02 ` Tony Wetmore
2003-08-26 15:16   ` Martin Voelkle

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).