Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

String building

76 views
Skip to first unread message

woodb...@gmail.com

unread,
May 19, 2013, 5:01:17 PM5/19/13
to
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::ostringstream 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

woodb...@gmail.com

unread,
May 19, 2013, 5:19:17 PM5/19/13
to
On Sunday, May 19, 2013 9:01:17 PM UTC, woodb...@gmail.com wrote:
> 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::ostringstream 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.

Ian Collins

unread,
May 19, 2013, 5:51:57 PM5/19/13
to
What append version? You don't show it.

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

--
Ian Collins

woodb...@gmail.com

unread,
May 19, 2013, 6:18:20 PM5/19/13
to
On Sunday, May 19, 2013 9:51:57 PM UTC, Ian Collins wrote:
>
> 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.)

Ian Collins

unread,
May 19, 2013, 6:23:23 PM5/19/13
to
Your failure class doesn't have an append method.

--
Ian Collins

woodb...@gmail.com

unread,
May 19, 2013, 6:34:13 PM5/19/13
to
On Sunday, May 19, 2013 10:23:23 PM UTC, Ian Collins wrote:
>
>
> 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.

Joshua Maurice

unread,
May 20, 2013, 12:05:53 AM5/20/13
to
On May 19, 2:01 pm, woodbria...@gmail.com wrote:
> 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?

Ike Naar

unread,
May 20, 2013, 12:57:17 AM5/20/13
to
On 2013-05-19, woodb...@gmail.com <woodb...@gmail.com> wrote:
> template <class T>
> failure& operator<< (T val)
> {
> ::std::ostringstream ss;
> ss << val;
> whatStr.append(ss.str().c_str());

why not

whatStr.append(ss.str());

?

woodb...@gmail.com

unread,
May 20, 2013, 12:06:14 PM5/20/13
to
On Sunday, May 19, 2013 11:05:53 PM UTC-5, Joshua Maurice wrote:
>
> Did you use the standard optimizer settings for the compiler and
>
> linker? What settings did you use?

The makefile is here --
http://webEbenezer.net/misc/makefile

I think it has -O3 for optimization.

woodb...@gmail.com

unread,
May 20, 2013, 12:17:03 PM5/20/13
to
On Sunday, May 19, 2013 11:57:17 PM UTC-5, Ike Naar wrote:
>
> 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::ostringstream ss;
ss << val;
return operator<<(ss.str().c_str());
}

Ike Naar

unread,
May 20, 2013, 1:16:00 PM5/20/13
to
On 2013-05-20, woodb...@gmail.com <woodb...@gmail.com> wrote:
> On Sunday, May 19, 2013 11:57:17 PM UTC-5, Ike Naar wrote:
>> 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.

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());

Ian Collins

unread,
May 20, 2013, 4:01:44 PM5/20/13
to
Rather than adding a specialisation to the class, I would add them outside:

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

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

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

--
Ian Collins

woodb...@gmail.com

unread,
May 20, 2013, 9:22:59 PM5/20/13
to
On Monday, May 20, 2013 8:01:44 PM UTC, Ian Collins wrote:
>
> 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.

Ian Collins

unread,
May 20, 2013, 9:37:07 PM5/20/13
to
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::ostream.

--
Ian Collins

woodb...@gmail.com

unread,
May 20, 2013, 11:21:17 PM5/20/13
to
On Monday, May 20, 2013 8:01:44 PM UTC, Ian Collins wrote:
>
> Rather than adding a specialisation to the class, I would add them outside:
>
>
> template <>
> failure& failure::operator<<( 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.
0 new messages