String building

W

woodbrian77

I have this class:

class failure : public ::std::exception {
::std::string whatStr;

public:
explicit failure :):std::string what_) : whatStr:):std::move(what_))
{}

~failure () throw()
{}

char const* what () const throw()
{ return whatStr.c_str(); }

template <class T>
failure& operator<< (T val)
{
::std::eek:stringstream ss;
ss << val;
whatStr.append(ss.str().c_str());
return *this;
}
};


If in some function I write this:

throw failure("Getaddrinfo: ") << gai_strerror(err); // << version

the executable/output from clang 3.2 is 96 bytes more than
if I write it this way:

throw failure:):std::string("Getaddrinfo: ").append(gai_strerror(err)));

Using g++ 4.8.0 20130310, the executable for the "<< version"
is 120 bytes larger than the version that uses string::append.

While looking at this, one thing I tried was changing this:

failure& operator<< (T val)

to
failure& operator<< (T const& val)

but the size of one executable increased by about 9%
(over 5,000 bytes) when I tried that.

Do you suggest going with the append version? Any
other options? Tia.


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net
 
W

woodbrian77

I have this class:



class failure : public ::std::exception {

::std::string whatStr;



public:

explicit failure :):std::string what_) : whatStr:):std::move(what_))

{}



~failure () throw()

{}



char const* what () const throw()

{ return whatStr.c_str(); }



template <class T>

failure& operator<< (T val)

{

::std::eek:stringstream ss;

ss << val;

whatStr.append(ss.str().c_str());

return *this;

}

};





If in some function I write this:



throw failure("Getaddrinfo: ") << gai_strerror(err); // << version



the executable/output from clang 3.2 is 96 bytes more than

if I write it this way:



throw failure:):std::string("Getaddrinfo: ").append(gai_strerror(err)));



Using g++ 4.8.0 20130310, the executable for the "<< version"

is 120 bytes larger than the version that uses string::append.

I guess both versions use append. I mean here the
version that uses append at the top level.
 
I

Ian Collins

I have this class:

class failure : public ::std::exception {
::std::string whatStr;

public:
explicit failure :):std::string what_) : whatStr:):std::move(what_))
{}

~failure () throw()
{}

char const* what () const throw()
{ return whatStr.c_str(); }

template <class T>
failure& operator<< (T val)
{
::std::eek:stringstream ss;
ss << val;
whatStr.append(ss.str().c_str());
return *this;
}
};


If in some function I write this:

throw failure("Getaddrinfo: ") << gai_strerror(err); // << version

the executable/output from clang 3.2 is 96 bytes more than
if I write it this way:

throw failure:):std::string("Getaddrinfo: ").append(gai_strerror(err)));

Using g++ 4.8.0 20130310, the executable for the "<< version"
is 120 bytes larger than the version that uses string::append.

While looking at this, one thing I tried was changing this:

failure& operator<< (T val)

to
failure& operator<< (T const& val)

but the size of one executable increased by about 9%
(over 5,000 bytes) when I tried that.

Do you suggest going with the append version? Any
other options? Tia.

What append version? You don't show it.

By the way, please don't double space your replies!
 
W

woodbrian77

What append version? You don't show it.

throw failure("Getaddrinfo: ") << gai_strerror(err); // version 1

throw failure:):std::string("Getaddrinfo: ").append(gai_strerror(err))); // version 2

I mean the line that I commented as version 2. (That is
shown in the original post.)
 
I

Ian Collins

throw failure("Getaddrinfo: ") << gai_strerror(err); // version 1

throw failure:):std::string("Getaddrinfo: ").append(gai_strerror(err))); // version 2

I mean the line that I commented as version 2. (That is
shown in the original post.)

Your failure class doesn't have an append method.
 
W

woodbrian77

Your failure class doesn't have an append method.

I just added this to the failure class

failure& operator<< (char const* str)
{
whatStr.append(str);
return *this;
}

And now the executable is building smaller. Thanks.
 
J

Joshua Maurice

Using g++ 4.8.0 20130310, the executable for the "<< version"
is 120 bytes larger than the version that uses string::append.

Did you use the standard optimizer settings for the compiler and
linker? What settings did you use?
 
W

woodbrian77

why not


whatStr.append(ss.str());


?

I think the reason I had it the other way was because
it was a little smaller in terms of the size of the
executable -- not the most profound reason, but that's
probably what it was -- maybe 16 or 32 bytes smaller.

I did check that again recently and remembered that
there was a potential reason for using c_str()
there.

I reworked that function now to use the char const*
version that I added:

failure& operator<< (char const* str)
{
whatStr.append(str);
return *this;
}

template <class T>
failure& operator<< (T val)
{
::std::eek:stringstream ss;
ss << val;
return operator<<(ss.str().c_str());
}
 
I

Ike Naar

I think the reason I had it the other way was because
it was a little smaller in terms of the size of the
executable -- not the most profound reason, but that's
probably what it was -- maybe 16 or 32 bytes smaller.

I did check that again recently and remembered that
there was a potential reason for using c_str()
there.

Interesting. With gcc (NetBSD nb2 20110806) 4.5.3
it's the other way around:

whatStr.append(ss.str());

procuces smaller executable code than

whatStr.append(ss.str().c_str());
 
I

Ian Collins

I think the reason I had it the other way was because
it was a little smaller in terms of the size of the
executable -- not the most profound reason, but that's
probably what it was -- maybe 16 or 32 bytes smaller.

I did check that again recently and remembered that
there was a potential reason for using c_str()
there.

I reworked that function now to use the char const*
version that I added:

failure& operator<< (char const* str)
{
whatStr.append(str);
return *this;
}

template <class T>
failure& operator<< (T val)
{
::std::eek:stringstream ss;
ss << val;
return operator<<(ss.str().c_str());
}

Rather than adding a specialisation to the class, I would add them outside:

template <>
failure& failure::eek:perator<<( const std::string& s )
{
whatStr.append(s);
return *this;
}

template <>
failure& failure::eek:perator<<( const char* s )
{
whatStr.append(s);
return *this;
}

You can apply the same technique with any other types you want to append.
 
W

woodbrian77

Rather than adding a specialisation to the class, I would add them outside:

What's the reason for that? I've heard of that but
can't remember why that is suggested.
 
I

Ian Collins

What's the reason for that? I've heard of that but
can't remember why that is suggested.

One of the advantages of C++ is you don't have to keep updating a class
in order to specialise template member functions. Consider the case
where you can't change the class. It's similar in a way to adding user
defined output operators instead of updating std::eek:stream.
 
W

woodbrian77

Rather than adding a specialisation to the class, I would add them outside:


template <>
failure& failure::eek:perator<<( const std::string& s )
{
whatStr.append(s);
return *this;
}

I knew that adding an overload for std::string made sense,
but was surprised by how the executable shrank by about
2,000 bytes with that in there. I don't see any where
I'm appending a std::string object to an exception message
when I throw. I have some code like this

throw failure("Read -- read len: ") << len << " errno: " << errno;

and figured " errno: " would match the char const* version.
 

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,808
Messages
2,569,686
Members
45,454
Latest member
FionaValli

Latest Threads

Top