From: Francis Glassborow on
Andrew wrote:
> On 2 Dec, 21:59, "A. McKenney" <alan_mckenn...(a)yahoo.com> wrote:
>> Warning: I'm not entirely on your side.
>
>> Another approach if you have reason to worry
>> about the inefficiency of copying std::string
>> is to "roll your own"
>
> I want to return by value and I am not worried about the performance
> of this. The opposition is worried about performance but has no
> figures or any other reason to back this up. It is just "more
> efficient". I have run into this attitude many many times. It is quite
> normal for people to argue for one construct over another in the name
> of performance without even knowing if perfornance is an issue in that
> area.
>

The problem is that performance figures are highly dependant on
implementations. We know (not speculation) that copy constructing a
string with the kind of implementation that was the norm in the 90's is
expensive (so much so that COW was considered a strong contender despite
problems with multi-threading). More recently most implementations have
switched to using the small string optimisation. That makes copying for
small strings much less expensive.

The problem with references is ensuring that we do not create a hanging
reference. The problem with copying is the potential cost of doing so.

Now the real problem comes down to programmers who want to have
universal 'rules'. I.e. they do not want to have to think. The situation
of returning a string member from a class object is quite different to
returning a non-member from a function.

Interface design is not for the lazy :)

Note that we also need to consider whether the caller may want only the
current value or to be able to track the value. That leads to me
wondering whether we should not sometimes return a const volatile reference.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Stuart Golodetz on
Goran wrote:
> On Dec 2, 10:58 pm, Stuart Golodetz
> <sgolod...(a)NdOiSaPlA.pMiPpLeExA.ScEom> wrote:
>> X x;
>> const std::string& r = x.s(); // affected by subsequent x destruction
>> std::string s = x.s(); // not affected by subsequent x destruction
>
>
> Whoa, stop, that's wrong! r is __not__ affected by x destruction,
> because x gets destroyed __after__ r (sort to speak). Try thinking
> like this, instead (that's what standard requires WRT variable
> construction-destruction):
>
> { // x only available in this block
> X x;
> { // r only available in this block
> const std::string& r = x.s();
> { // s only available in this block
> std::string s = x.s();
> }
> }
> }
>
> As you can see, it's not possible for r to be bad due to destroyed x.
> What __is__ possible (and people make that mistake), is that you
> somehow copy the reference somehow (to a pointer) and keep that after
> x is destroyed, e.g.
>
> const std::string* p;
> {
> X x;
> const std::string& r = x.s(); // affected by subsequent x
> destruction
> p = &x; // Whoops!
> std::string s = x.s(); // not affected by subsequent x destruction
> }
> p == "Undefined behavior";
>
> Goran.

It wasn't supposed to be a literal (or complete) example. Here's a
better one:

#include <iostream>
#include <string>

#include <boost/shared_ptr.hpp>
using boost::shared_ptr;

struct X
{
std::string m_s;

X() : m_s("Wibble") {}

const std::string& s() const
{
return m_s;
}
};

int main()
{
shared_ptr<X> x(new X);
const std::string& r = x->s();
x.reset();

// BOOM
std::cout << r << '\n';

return 0;
}

Regards,
Stu

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Martin B. on
Andrew wrote:
> On 2 Dec, 22:00, Zachary Turner <divisorthe...(a)gmail.com> wrote:
>> On Dec 2, 7:06 am, Andrew <marlow.and...(a)googlemail.com> wrote:
>>
>> Maybe I'm overlooking something, but I see little reason to return by
>> value. What matters is whether you assign it to a const reference or
>> to a value.
>
> The view I am running into is that a function should return a const
> ref to a string so that it can be assigned to a const ref to a string.
> The argument is that doing this avoids string copying. I should have
> made that clearer.
>

I don't like that argument. If I need to hold a string I need to hold a
string and not some reference to some internals of some object.

Note also that:
class Foo {
string s_;
public:
string get_s() { return s; }
string const& access_s() { return s; }
};
....
string x = obj.get_s();
string y = obj.access_s();
// Because of RVO, these two calls will copy the string exactly one
time, so ret-by-val does not decrease performance

string const& rz = obj.access_s();
// Generally saves one heap allocation, so is faster.
// However validity of rz is tightly coupled to state and lifetime of
obj, so the likelihood of crashes increases.

br,
Martin

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Stuart Golodetz on
Goran wrote:
> On Dec 2, 10:58 pm, Stuart Golodetz
> <sgolod...(a)NdOiSaPlA.pMiPpLeExA.ScEom> wrote:
>> X x;
>> const std::string& r = x.s(); // affected by subsequent x destruction
>> std::string s = x.s(); // not affected by subsequent x destruction
>
>
> Whoa, stop, that's wrong! r is __not__ affected by x destruction,
> because x gets destroyed __after__ r (sort to speak). Try thinking
> like this, instead (that's what standard requires WRT variable
> construction-destruction):
>
> { // x only available in this block
> X x;
> { // r only available in this block
> const std::string& r = x.s();
> { // s only available in this block
> std::string s = x.s();
> }
> }
> }
>
> As you can see, it's not possible for r to be bad due to destroyed x.
> What __is__ possible (and people make that mistake), is that you
> somehow copy the reference somehow (to a pointer) and keep that after
> x is destroyed, e.g.
>
> const std::string* p;
> {
> X x;
> const std::string& r = x.s(); // affected by subsequent x
> destruction
> p = &x; // Whoops!
> std::string s = x.s(); // not affected by subsequent x destruction
> }
> p == "Undefined behavior";
>
> Goran.

To clarify my original post, what I was getting at was that r would be
affected were x destroyed somehow. I didn't mean to imply that all the
variables were within one function - my bad. I guess this is why
minimal, complete code examples are recommended (because what is
effectively pseudo-code can be misleading).

Stu

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Nevin :-] Liber on
In article <6LednaHXT5qNForWnZ2dnUVZ8mWdnZ2d(a)bt.com>,
Francis Glassborow <francis.glassborow(a)btinternet.com> wrote:

> Note that we also need to consider whether the caller may want only the
> current value or to be able to track the value. That leads to me
> wondering whether we should not sometimes return a const volatile reference.

Could you elaborate on why one would need volatile?

As you well know, all that const reference means is that the intention
is not to modify the object through this alias (mutable, const_cast,
etc. notwithstanding, of course).

--
Nevin ":-)" Liber <mailto:nevin(a)eviloverlord.com> 773 961-1620

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]