std::stringstream returning back values

T

TBass

Hi.

I wrote a "tag" class to store values. The user gets to store most any
type he would need. Instead of getting too complicatated, I decided I
would store the value as a stringstream, then overload the SetValue
method.

....

protected:
std::stringstream m_szValue;

....


void
CFusionTag::SetValue( char *szValue )
{
m_szValue << szValue;

MessageBox::Show( m_szValue.str().c_str() );

} /* ::SetValue */


void
CFusionTag::SetValue( unsigned int uiValue )
{
m_szValue << uiValue;
}

void
CFusionTag::SetValue( int iValue )
{
m_szValue << iValue;
}

void
CFusionTag::SetValue( float fValue )
{
m_szValue << fValue;
}

void
CFusionTag::SetValue( double dValue )
{
m_szValue << dValue;
}

void
CFusionTag::SetValue( long lValue )
{
m_szValue << lValue;
}


That works fine (I'm aware of the obvious flaw in this code, but I use
taking advantage of that for debugging purposes). The value gets
stored.

My problem (which is probably obvious to everyone but me) is returning
the value when someone calls the GetValue method.

void
CFusionTag::GetValue( char *szValue )
{

MessageBox::Show( "Sending back a char value!" );
szValue = (char *)m_szValue.str().c_str();
}

The char string returned is always blank. I thought this would be
pretty simple, but STL keeps getting the better of me. Can anyone
point me in the right direction?

Thanks in advance,
T
 
T

TBass

I don't know if this would be the "C++" way, but doing it the way I
would do it in C worked.

void
CFusionTag::GetValue( char *szValue )
{
memcpy( szValue, m_szValue.str().c_str(), m_szValue.str().length() );
}
 
D

Daniel T.

TBass said:
Hi.

I wrote a "tag" class to store values. The user gets to store most any
type he would need. Instead of getting too complicatated, I decided I
would store the value as a stringstream, then overload the SetValue
method.

...

protected:
std::stringstream m_szValue;

...


void
CFusionTag::SetValue( char *szValue )
{
m_szValue << szValue;

MessageBox::Show( m_szValue.str().c_str() );

} /* ::SetValue */


void
CFusionTag::SetValue( unsigned int uiValue )
{
m_szValue << uiValue;
}

void
CFusionTag::SetValue( int iValue )
{
m_szValue << iValue;
}

void
CFusionTag::SetValue( float fValue )
{
m_szValue << fValue;
}

void
CFusionTag::SetValue( double dValue )
{
m_szValue << dValue;
}

void
CFusionTag::SetValue( long lValue )
{
m_szValue << lValue;
}


That works fine (I'm aware of the obvious flaw in this code, but I use
taking advantage of that for debugging purposes). The value gets
stored.

My problem (which is probably obvious to everyone but me) is returning
the value when someone calls the GetValue method.

void
CFusionTag::GetValue( char *szValue )
{

MessageBox::Show( "Sending back a char value!" );
szValue = (char *)m_szValue.str().c_str();
}

The char string returned is always blank.

Your not returning anything. Try this:

std::string
CFusionTag::GetValue() const
{
return m_szValue.str();
}
I thought this would be pretty simple, but STL keeps getting the
better of me. Can anyone point me in the right direction?

Your having problems because you are trying to use C idioms (char*)
instead of C++ idioms (string.)
 
Z

zhangyw80

I don't know if this would be the "C++" way, but doing it the way I
would do it in C worked.

void
CFusionTag::GetValue( char *szValue )
{
memcpy( szValue, m_szValue.str().c_str(), m_szValue.str().length() );



}- Òþ²Ø±»ÒýÓÃÎÄ×Ö -

- ÏÔʾÒý
the folowing is another C way through passing argument by pointer:
void
CFusionTag::GetValue(const char** szValue)
{
if(szValue != NULL)
{
*szValue = m_szValue.str().c_str();
}
}
 
A

acehreli

Hmmm... Do we have enough space at szValue? Probably not! :(
the folowing is another C way through passing argument by pointer:
void
CFusionTag::GetValue(const char** szValue)
{
if(szValue != NULL)
{
*szValue = m_szValue.str().c_str();

That doesn't work... The std::string value that str() returns is a
temporary object that dies at the semicolon. So, the C-style string
that is returned by c_str() is not valid beyond that point.

Ali
 
T

TBass

That doesn't work... The std::string value that str() returns is a
temporary object that dies at the semicolon. So, the C-style string
that is returned by c_str() is not valid beyond that point.


Ah ha! That's been my problem. I did not know that it was temporary.
Thanks!


[snip]
I thought this would be pretty simple, but STL keeps getting the
better of me. Can anyone point me in the right direction?

Your having problems because you are trying to use C idioms (char*)
instead of C++ idioms (string.)
[/snip]

The reason for the char * as an argument was because it's actually a
vector that I'm passing into the structure.

std::vector<char> myvector(500);
mytag->GetValue( &myvector[0] );
 
D

Daniel T.

TBass said:
That doesn't work... The std::string value that str() returns is a
temporary object that dies at the semicolon. So, the C-style string
that is returned by c_str() is not valid beyond that point.


Ah ha! That's been my problem. I did not know that it was temporary.
Thanks!


[snip]
I thought this would be pretty simple, but STL keeps getting the
better of me. Can anyone point me in the right direction?

Your having problems because you are trying to use C idioms (char*)
instead of C++ idioms (string.)
[/snip]

The reason for the char * as an argument was because it's actually a
vector that I'm passing into the structure.

std::vector<char> myvector(500);
mytag->GetValue( &myvector[0] );

Creating a buffer and assuming it is big enough (or making it insanely
huge) is a (rather poor) C idiom. Better would be:


string str = mytag->GetValue();
std::vector<char> myvector( str.begin(), str.end() );

Even having the function fill a vector that is provided would be better
than using the raw char*.

std::vector<char> myvector;
mytag->GetValue( back_inserter( myvector ) );
 
D

Daniel T.

TBass said:
I don't know if this would be the "C++" way, but doing it the way I
would do it in C worked.

void
CFusionTag::GetValue( char *szValue )
{
memcpy( szValue, m_szValue.str().c_str(), m_szValue.str().length() );
}

What if the block passed in isn't big enough? At the very least, even in
C, you should pass in the size of the block handed over...

void
CFusionTag::GetValue( char* value, int value_size ) {
memcpy( value, m_szValue.str().c_str(),
std::min( value_size, m_szValue.str().length() ) );
}

The fact that you are having to chain the calls (like
"m_szValue.str().c_str()" and "m_szValue.str().length()") means there is
probably an easier way.
 
J

Jerry Coffin

[ ... ]
The reason for the char * as an argument was because it's actually a
vector that I'm passing into the structure.

std::vector<char> myvector(500);
mytag->GetValue( &myvector[0] );

So if it's actually a vector, pass it as a vector. Better still, pass an
iterator:

template <class OutIter>
void CFusionTag::GetValue(OutIter out)
{
std::string const &s=m_szValue.str();

std::copy(s.begin(), s.end(), out);
}

std::vector<char> myvector;
mytag.GetValue(std::back_inserter(myvector));

This helps with both versatility and safety. In fairness, it's pretty
still pretty easy to use it in an usafe fashion, about like you were
before, such as:

std:veector<char> myvector(500);

mytag.GetValue(myvector.begin());

Now, if you've put more than 500 characters of data into the CFusionTag
object, you're going to overrun the buffer just like you would have
before. OTOH, even though this code can be misused, at least it's
_possible_ to use it safely, which wasn't really possible with the other
version.

BTW, this code provides a superb example of why Hungarian Notation is
such a lousy idea. You've used the name m_szValue, but in reality what
you have is NOT a zero terminated string at all -- it's a stringstream.
You've be MUCH better off just calling it value (or Value if you insist
on capitalizing it). The leading 'm_' isn't quite as harmful, but it's
still pointless at best, and hurts readability.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,120
Latest member
ShelaWalli
Top