473,491 Members | 2,008 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Returning by value (here we go again!)


AnyClass Blah()
{
AnyClass poo;

return poo;
}
As we all know, in the above, the compiler is entitled to:

1) Create the object "poo"
2) Create a copy of "poo"
3) Destroy "poo"
4) Return the copy

or

1) Create the object "poo"
2) Return "poo"
On account of the first choice, whether a copy is made or not, the copy
constructor must be public.

First of all, I think it would be handy if we had a new type of "return"
statement in C++, one which makes it so that the actual object is returned
(no copy made) and as such the copy constructor wouldn't need to be
public... allowing the likes of the following:

std::ostream Blah()
{
std::ostream poo;

return_actual_object poo;
}
Anyway...

To achieve this, at the moment I'm using auto_ptr, as follows:

auto_ptr<AnyClass> Blah()
{
auto_ptr<AnyClass> poo( new AnyClass );

return poo;
}

int main()
{
auto_ptr<AnyClass> const &milk = Blah();

//now work with it as I please!
//and if I want reference syntax:

AnyClass const& cheese = *milk;

cheese.MemberFunction();
}
The compiler still has the choice of copying the auto_ptr... but it's a hell
of a lot better than copying the entire object! Plus, I can return an
"std::ostream" by value... (kind of!).

AAnnyywwaayy... looking through a C++ reference today I was sort of shocked
to see:

basic_string::substr
basic_string substr(size_type off = 0,
size_type count = npos) const;
The member function returns an object whose controlled sequence is a copy of
up to count elements of the controlled sequence beginning at position off.
It returns by value! AAAAAAaaahhhhhhhh! throw Inefficiency(); !
-JKop

Jul 22 '05 #1
11 1908
JKop wrote:


First of all, I think it would be handy if we had a new type of "return"
statement in C++, one which makes it so that the actual object is returned
(no copy made) and as such the copy constructor wouldn't need to be
public... allowing the likes of the following:

std::ostream Blah()
{
std::ostream poo;

return_actual_object poo;
}
The problem with this is not the return.
The problem is that copying a stream object is forbidden.

As for your suggestion.
Now we have a simple rule: Every local object gets destroyed at the
end of the function. Your suggestion would make an exception to that.
What would be scope of that local object? In other words: when
does it get destroyed?

Anyway...

To achieve this, at the moment I'm using auto_ptr, as follows:

auto_ptr<AnyClass> Blah()
{
auto_ptr<AnyClass> poo( new AnyClass );

return poo;
}
Fine. In other words: You dynamically allocate the object
and ask the caller to free it. Fine. In order to help
the caller somewhat, you put an envelope around it. Also
fine.

[snip]
The compiler still has the choice of copying the auto_ptr... but it's a hell
of a lot better than copying the entire object! Plus, I can return an
"std::ostream" by value... (kind of!).

AAnnyywwaayy... looking through a C++ reference today I was sort of shocked
to see:

basic_string::substr
basic_string substr(size_type off = 0,
size_type count = npos) const;
The member function returns an object whose controlled sequence is a copy of
up to count elements of the controlled sequence beginning at position off.

It returns by value! AAAAAAaaahhhhhhhh! throw Inefficiency(); !


You should not be shocked.

string a = "abcd";
string b = a.substr(2) + "xyz";

In order for this to work, there is no other choice as to return a copy.
Return value optimization takes care of the rest.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #2
In article <Ar*******************@news.indigo.ie>,
JKop <NU**@NULL.NULL> wrote:
First of all, I think it would be handy if we had a new type of "return"
statement in C++, one which makes it so that the actual object is returned
(no copy made) and as such the copy constructor wouldn't need to be
public... allowing the likes of the following:

std::ostream Blah()
{
std::ostream poo;

return_actual_object poo;
}
I agree, at least partly. This can be achieved with move semantics:

http://www.open-std.org/jtc1/sc22/wg...004/n1690.html
http://www.open-std.org/jtc1/sc22/wg...2002/n1377.htm

which unfortunately is not part of C++ today. If you would like to see
move semantics become part of C++, make sure your national
representative on the C++ committee knows that.

Movable, but non-copyable types with non-cv qualified auto storage
should be returnable by value from functions. For example see:

http://www.open-std.org/jtc1/sc22/wg...77.htm#Moving%
20from%20local%20values

std::streams could be made movable, and remain non-copyable.
Anyway...

To achieve this, at the moment I'm using auto_ptr, as follows:

auto_ptr<AnyClass> Blah()
{
auto_ptr<AnyClass> poo( new AnyClass );

return poo;
}

int main()
{
auto_ptr<AnyClass> const &milk = Blah();

//now work with it as I please!
//and if I want reference syntax:

AnyClass const& cheese = *milk;

cheese.MemberFunction();
}
<nod> Today's workarounds are ugly.
AAnnyywwaayy... looking through a C++ reference today I was sort of shocked
to see:

basic_string::substr
basic_string substr(size_type off = 0,
size_type count = npos) const;
The member function returns an object whose controlled sequence is a copy of
up to count elements of the controlled sequence beginning at position off.

It returns by value! AAAAAAaaahhhhhhhh! throw Inefficiency(); !


A good compiler can optimize away this copy if the client is using
substr to construct another string. But if it is using substr to assign
into an existing string a temporary is still created.

It would be a lot more palatable with move semantics. The temporary
could still be created, but then it would be moved from, instead of
copied from.

-Howard
Jul 22 '05 #3

"JKop" <NU**@NULL.NULL> wrote in message
news:Ar*******************@news.indigo.ie...

AnyClass Blah()
{
AnyClass poo;

return poo;
}
As we all know, in the above, the compiler is entitled to:

1) Create the object "poo"
2) Create a copy of "poo"
3) Destroy "poo"
4) Return the copy

or

1) Create the object "poo"
2) Return "poo"

or optimize away the function call to Blah and create the AnyClass object at
the point of the function call instead. However, whether this can be done
and makes sense depends on the context.

On account of the first choice, whether a copy is made or not, the copy
constructor must be public.
Well, what´s the problem with that. Declaring the copy ctor
private/protected is an idiom that signals that no copy can be created.

First of all, I think it would be handy if we had a new type of "return"
statement in C++, one which makes it so that the actual object is returned
(no copy made) and as such the copy constructor wouldn't need to be
public... allowing the likes of the following:

std::ostream Blah()
{
std::ostream poo;

return_actual_object poo;
}

As Karl Heinz already mentioned there is the issue of scope and automatic
destruction, which makes absolutely sense. Otherwise we´re going into the
C#, Java etc. direction where garbage control ist needed. The pros & cons of
GC are a topic themselves.

Anyway...

To achieve this, at the moment I'm using auto_ptr, as follows:

auto_ptr<AnyClass> Blah()
{
auto_ptr<AnyClass> poo( new AnyClass );

return poo;
}

int main()
{
auto_ptr<AnyClass> const &milk = Blah();

//now work with it as I please!
//and if I want reference syntax:

AnyClass const& cheese = *milk;

cheese.MemberFunction();
}

So you´re using a pointer with transferable ownership but you´re heading in
the direction where you clutter your code with mostly unnecessary
constructions like that. With a proper design such things should rarely be
required.

The compiler still has the choice of copying the auto_ptr... but it's a hell of a lot better than copying the entire object! Plus, I can return an
"std::ostream" by value... (kind of!).
BTW, copying streams is not allowed.

AAnnyywwaayy... looking through a C++ reference today I was sort of shocked to see:

basic_string::substr
basic_string substr(size_type off = 0,
size_type count = npos) const;
The member function returns an object whose controlled sequence is a copy of up to count elements of the controlled sequence beginning at position off.
It returns by value! AAAAAAaaahhhhhhhh! throw Inefficiency(); !


Hold you breath ;-) Returning by value instead of reference makes absolutely
sense in this case, as already pointed out by Karl Heinz. However, I´d
suggest that you read the respective chapter 23 in Scott Meyers "Effective
C++".

As he says: [quote] "It all boils down to this: when deciding between
returning a reference and returning an object, your job is to make the
choice that does the right thing. Let your compiler vendors wrestle with
figuring out how to make that choice as inexpensive as possible" [quote]

Chris
Jul 22 '05 #4
JKop wrote:
AnyClass Blah(void) {
AnyClass poo;
return poo;
}
As we all know, in the above, the compiler is entitled to:

1) Create the object "poo"
2) Create a copy of "poo"
3) Destroy "poo"
4) Return the copy

or

1) Create the object "poo"
2) Return "poo"
On account of the first choice, whether a copy is made or not,
the copy constructor must be public.

First of all, I think it would be handy if we had a new type of "return"
statement in C++, one which makes it so that the actual object is returned
(no copy made) and as such the copy constructor wouldn't need to be
public... allowing the likes of the following:

std::ostream Blah()
{
std::ostream poo;

return_actual_object poo;
}
Anyway...

To achieve this, at the moment I'm using auto_ptr, as follows:

auto_ptr<AnyClass> Blah()
{
auto_ptr<AnyClass> poo( new AnyClass );

return poo;
}

int main()
{
auto_ptr<AnyClass> const &milk = Blah();

//now work with it as I please!
//and if I want reference syntax:

AnyClass const& cheese = *milk;

cheese.MemberFunction();
}
The compiler still has the choice of copying the auto_ptr... but it's a hell
of a lot better than copying the entire object! Plus, I can return an
"std::ostream" by value... (kind of!).

AAnnyywwaayy... looking through a C++ reference today I was sort of shocked
to see:

basic_string::substr
basic_string substr(size_type off = 0,
size_type count = npos) const;
The member function returns an object whose controlled sequence is a copy of
up to count elements of the controlled sequence beginning at position off.
It returns by value! AAAAAAaaahhhhhhhh! throw Inefficiency(); !
You are confused.
cat main.cc #include <iostream>

class AnyClass {
private:
// representation
int I;
public:
// operators
friend
std::ostream& operator<<(std::ostream& os, const AnyClass& a);
// constructors
AnyClass(int i = 0): I(i) {
std::cout << "AnyClass::AnyClass(int)" << std::endl;
}
AnyClass(const AnyClass& a): I(a.I) {
std::cout << "AnyClass::AnyClass(const AnyClass&)"
<< std::endl;
}
~AnyClass(void) {
std::cout << "AnyClass::~AnyClass(void)" << std::endl;
}
};

inline
std::ostream& operator<<(std::ostream& os, const AnyClass& a) {
return os << a.I;
}

AnyClass Blah(void) {
AnyClass poo;
return poo;
}

int main(int argc, char* argv[]) {
AnyClass a = Blah();
std::cout << "a = " << a << std::endl;
return 0;
}
g++ -Wall -ansi -pedantic -o main main.cc
./main

AnyClass::AnyClass(int)
a = 0
AnyClass::~AnyClass(void)

1. ) The copy constructor is *never* called,
2. ) AnyClass(int) initializes the return value directly and
3. ) Blah(void) initializes object a directly.

You can't write code that is more efficient than that.
Jul 22 '05 #5
1. ) The copy constructor is *never* called,
With your particular compiler, yes.
2. ) AnyClass(int) initializes the return value directly and
With your particular compiler, yes.
3. ) Blah(void) initializes object a directly.
With your particular compiler, yes.
You can't write code that is more efficient than that.


With your particular compiler, yes.
What I'm getting at is that when you return an object by value, under the
duress of the Standard, the compiler is entitled to make copies and destroy
originals.
-JKop
Jul 22 '05 #6

"JKop" <NU**@NULL.NULL> schrieb im Newsbeitrag
news:Hs*******************@news.indigo.ie...
1. ) The copy constructor is *never* called,
With your particular compiler, yes.
2. ) AnyClass(int) initializes the return value directly and


With your particular compiler, yes.
3. ) Blah(void) initializes object a directly.


With your particular compiler, yes.
You can't write code that is more efficient than that.


With your particular compiler, yes.
What I'm getting at is that when you return an object by value, under the
duress of the Standard, the compiler is entitled to make copies and

destroy originals.


Of course it is and it makes good sense. If you return by value you actually
ask the compiler to create a copy - well, if it can avoid it the better. The
destruction of the original has nothing to do by return the object by value
but rather by reaching the end of scope.
Furthermore there are many cases where this behavior is absolutely desirable
as it's been pointed out for example by Karl Heinz. Check out Scott Meyers'
Effective C++ item 23.

Chris
Jul 22 '05 #7
JKop wrote:
1. ) The copy constructor is *never* called,


With your particular compiler, yes.
2. ) AnyClass(int) initializes the return value directly and


With your particular compiler, yes.
3. ) Blah(void) initializes object a directly.


With your particular compiler, yes.
You can't write code that is more efficient than that.


With your particular compiler, yes.

What I'm getting at is that when you return an object by value,
under the duress of the Standard,
the compiler is entitled to make copies and destroy originals.


Correct.
The C++ standard specifies the language and not the implementation.
The quality of the implementation is governed by the marketplace.
You are expect, as a responsible consumer,
to shop for a compiler that performs as required.
There are probably quality C++ compilers for virtually every platform
that might be a target for the code that you are writing.
Jul 22 '05 #8
JKop wrote:
AnyClass Blah()
{
AnyClass poo;

return poo;
}

As we all know, in the above, the compiler is entitled to:

1) Create the object "poo"
2) Create a copy of "poo"
3) Destroy "poo"
4) Return the copy

or

1) Create the object "poo"
2) Return "poo"
You're not actually looking at what happens at the end of Blah, you're
looking at the boundary between Blah and its caller. The second method
only happens when the compiler is able to merge part of the caller with
Blah, ie the second case doesn't skip creating the copy, it skips
creating poo.

As for actual implementation, this would have to happen before Blah
returned, because if poo is to be copied it still needs to exist. But
using the copy constructor works in the general case, whereas skipping
it will only work if you only call Blah in specific ways. That is, how
Blah can be optimized depends on the code that calls Blah rather than
Blah's code itself.

In particular:
AnyClass tar;
try
{
tar = Blah();
}
catch (...)
{
}
will not work if the copy is skipped. If poo's constructor throws and
it's "returning the actual object", tar is left in an inconsistent state.

As opposed to:
AnyClass tar = Blah();
where tar cannot be constructed at all if the constructor throws poo.

I think that a new type of return that always returned the object rather
than copying would have some very complicated consequences.

I suppose if you were really desperate, you could simulate how a
theoretical compiler might do it with something like:

AnyClass &Blah(void *carrots)
{
AnyClass *poo = new(carrots) AnyClass;

return *poo;
}

void Cactus(void)
{
char cement[sizeof AnyClass];
AnyClass &tar = Blah(cement);

tar.MemberFunction();

tar.~AnyClass();
}

hm... probably. Except you'd want some sort of template to automate
that mess.
AAnnyywwaayy... looking through a C++ reference today I was sort of shocked
to see:

basic_string::substr
basic_string substr(size_type off = 0,
size_type count = npos) const;
The member function returns an object whose controlled sequence is a copy of
up to count elements of the controlled sequence beginning at position off.

It returns by value! AAAAAAaaahhhhhhhh! throw Inefficiency(); !


Yeah, std::string is like that. But the alternative is far more
complex. (check out the string classes used in Mozilla)

-josh

Jul 22 '05 #9
> auto_ptr<AnyClass> Blah()
{
auto_ptr<AnyClass> poo( new AnyClass );

return poo;
}

Maybe I'm being dense but std::auto_ptr gets
removed when it exits scope, no?
int main()
{
auto_ptr<AnyClass> const &milk = Blah();


How can this work if the memory is overwritten by something else?
Jul 22 '05 #10
Duane Hebert posted:
auto_ptr<AnyClass> Blah()
{
auto_ptr<AnyClass> poo( new AnyClass );

return poo;
}

Maybe I'm being dense but std::auto_ptr gets
removed when it exits scope, no?


Correct. But a copy of it is made for it's destroyed. The copy is returned.

Furthermore, when you make a copy of an auto_ptr, when the original is
destroyed, it no longer calls "delete".
int main()
{
auto_ptr<AnyClass> const &milk = Blah();


How can this work if the memory is overwritten by something else?

Wha?
-JKop
Jul 22 '05 #11

"JKop" <NU**@NULL.NULL> wrote in message news:16*******************@news.indigo.ie...
Duane Hebert posted:
auto_ptr<AnyClass> Blah()
{
auto_ptr<AnyClass> poo( new AnyClass );

return poo;
}

Maybe I'm being dense but std::auto_ptr gets
removed when it exits scope, no?


Correct. But a copy of it is made for it's destroyed. The copy is returned.

Furthermore, when you make a copy of an auto_ptr, when the original is
destroyed, it no longer calls "delete".


Of course. Thanks.
Jul 22 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
2904
by: Mountain Man | last post by:
Hi, I'm having trouble with the foreach function. I'm using it twice inside a user defined function with two different arrays, and in the second instance it's returning the value of the first...
5
2159
by: Anthony Papillion II | last post by:
Hello Everyone, I have been having fits with a simple PHP script and I'm hoping it's something that someone here can help me with. Basically, when I execute the SQL statement directly on the...
3
4488
by: Jochen Zeischka | last post by:
I'm puzzled. When compiling this: template<class ValRes, class Val1, class Val2> Veld<ValRes>& mult(Veld<ValRes>& res, const Veld<Val1>& v1, const Veld<Val2>& v2) { // something return res; }...
28
3640
by: Yevgen Muntyan | last post by:
Hey, Consider the following code: void func (void) { } void func2 (void) {
6
2798
by: Kavya | last post by:
I was reading a book Test Your C++ Skills by Yashwant Kanetkar. There was a question in it Ques: Why constructors do not have return values? Ans :Constructors are called whenever an object is...
6
1064
by: rowe_newsgroups | last post by:
I just noticed this about value types and return values, and it kind of bugs me that the compiler won't treat it as an error, even with Option Strict On. Try this out: Option Strict On ...
5
1685
by: littlevikinggirl | last post by:
Hi, I posted a badly worded question last week so got no replies and am still struggling to figure out the problem myself. I have a table containing two fields, Location and Serial Number. I...
4
2384
omerbutt
by: omerbutt | last post by:
hi there i am making an application in which i have a drop down menu which onchange passes a value(this.value) to a js function which gets the value and calls an ajax routine and passes that value...
2
3151
by: chuckzter | last post by:
I'm in a bit of a pickle here. I need to pass the variable @uname which gets a value from a text box to a statement on one of my stored procedures in SQL server and return an output on my form. ...
0
6978
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7154
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
7190
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
6858
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
7360
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5451
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
4578
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3086
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
1392
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.