map of string to ostringstream

  • Follow


Hey everyone, what am I missing here?

Background: Essentially, I've got an array of C structures with string
names and values, but the array contains multiple entries of the same
name for several values, and I'm trying to convert this to a string
format where each entry is a unique name followed by a comma-separated
value list. I need to take two passes over the input list. The first
one gathers multiple values into a single list for each unique name,
the second pass builds the output string from the resulting map data.
I'm using a map of strings to ostringstreams, and I'm trying to use
map::insert to either insert a new pair, or locate the previously
inserted pair by name. In either case, I simply append the next value
on to the value string. I thought to build the map from a string name
and an ostringstream value because the value data has to be converted
from binary to string format, so I could just continue to append
values until I was done. For the second traversal, I use a vector of
map::iterators that I built during the first traversal in order to
maintain the original data order.

-------------

using namespace std;

string MakeNVString(NameValue * namevals, unsigned nvcnt)
{
   // build a map of names to comma-separated value string-streams
   // and a vector of iterators into the map ordered by input traversal
   map<string, ostringstream> avsmap;
   vector<map<string, ostringstream>::iterator> order;
   for (unsigned i = 0; i < nvcnt; i++)
   {
     // locate name by inserting the name and a new stream value
     pair<map<string, ostringstream>::iterator, bool> pr =
         avsmap.insert(map<string, ostringstream>::value_type(
             string((char*)namevals[i].name),
             ostringstream()));

     // if insert succeeded, save iterator in traversal order vector
     // else it already exists, so prepend a comma before next value
     ostringstream & vs = pr.first->second;
     if (pr.second)
       order.push_back(pr.first);
     else
       vs << ',';

     // add the value string to the value stream
     switch(namevals[i].valueType)
     {
       case NS_VALUE_TYPE_STRINGZ:
         vs << (char*)namevals[i].value;
         break;

       // more cases ...

     }
   }

   // build the return string from the intermediate map
   ostringstream os;
   for (vector<map<string, ostringstream>::iterator>::iterator
       vp = order.begin(); vp != order.end(); ++vp)
   {
     map<string, ostringstream>::iterator ip = *vp;
     os << '(' << ip->first << '=' << ip->second.str() << ')';
   }
   return os.str();
}

-------------

Problem: The trouble is that my ostringstream objects don't get any
data inserted. I get the names back properly from the first map value
component (the string), but the ostringstream is (apparently) empty.
I'm probably doing something stupid like writing to a temporary object
somewhere instead of the ostringstream in my map-building loop, but I
can't see it.

Any ideas?

Thanks in advance,
John

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply jcalcote 11/18/2003 11:53:55 AM

John Calcote wrote:

> string MakeNVString(NameValue * namevals, unsigned nvcnt)
> {
>    // build a map of names to comma-separated value string-streams
>    // and a vector of iterators into the map ordered by input traversal
>    map<string, ostringstream> avsmap;

This is undefined behaviour.  23.1/3 says that objects
stored in Standard Library containers must be
CopyConstructible.  The ostringstream type cannot be copied
as it derives from basic_ios<char> which has a private copy
constructor and assignment operator.

As an alternative, how about using a

  boost::shared_ptr< std::ostringstream >

in the map?

>      pair<map<string, ostringstream>::iterator, bool> pr =
>          avsmap.insert(map<string, ostringstream>::value_type(
>              string((char*)namevals[i].name),
>              ostringstream()));

I'm surprised this compiles.  The value_type of a std::map
is a std::pair, and constructing a std::pair from two
objects will copy each of the objects.  As ostringstream has
an inaccessible copy constructor, I don't see how this can
compile.

> I'm probably doing something stupid like writing to a temporary object
> somewhere instead of the ostringstream in my map-building loop, but I
> can't see it.

I can easily believe this.  You apparently have a non-
conformant Standard Library implementation that allows
ostringstreams to be copied.  If instead of raw
ostringstreams, you hold them by shared pointer, it won't
matter whether or not you are writing to a temporary object.

--
Richard Smith

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Richard 11/18/2003 8:00:16 PM


On 18 Nov 2003 06:53:55 -0500, jcalcote@novell.com (John Calcote)
wrote:

>   map<string, ostringstream> avsmap;

That's illegal. ostringstream doesn't satisfy the container element
requirements since it isn't copyable. You need something like:

map<string, ostringstream*> avsmap;
or
map<string, shared_ptr<ostringstream> > avsmap;

Tom

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply tom_usenet 11/18/2003 8:07:39 PM

Thanks so much for the reply. 

> This is undefined behaviour.  23.1/3 says that objects
> stored in Standard Library containers must be
> CopyConstructible.  The ostringstream type cannot be copied
> as it derives from basic_ios<char> which has a private copy
> constructor and assignment operator.

I figured this out after switching from VC6 to VC7, which apparently
does a better job of only allowing that which is legal (not perfect,
but much better). Also the error messages are a bit more intelligible.

> As an alternative, how about using a
> 
>   boost::shared_ptr< std::ostringstream >

I actually reverted to string and got it working without too much
fuss, but I really like the idea of shared_ptr(ostringstream). That's
a neat idea - I may go back to that method just for fun. The problem
with my string implementation is that concatenation of strings is not
nearly as efficient as ostringstream insertion.

Thanks again,
John

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply jcalcote 11/19/2003 6:40:05 PM

3 Replies
406 Views

(page loaded in 0.061 seconds)

Similiar Articles:











7/19/2012 7:10:37 PM


Reply: