Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Trying to understand "&&"

Reply
Thread Tools

Trying to understand "&&"

 
 
Chameleon
Guest
Posts: n/a
 
      01-01-2011
I thought I understood the "&&" until the following simple example did
not work.
Can someone tell me which is the problem or what I did not understand?

It add 2 strings and "cout" the result.

Special thanks for your time!

------------------
g++ -std=c++0x main.cpp
------------------

-- main.cpp ------
#include <iostream>
#include <cstring>
using namespace std;

class A
{
public:
A() : str(0) { cout << "A()" << endl; }
A(const char *string) : str(0) { str = new char[strlen(string) + 1];
strcpy(str, string); cout << "A(const char*)" << endl; }
~A() { delete[] str; cout << "~A()" << endl; }
A(A &a) : str(0) { str = new char[strlen(a.str) + 1]; strcpy(str,
a.str); cout << "A(A&)" << endl; }
A(A &&a) : str(0) { str = a.str; a.str = 0; cout << "A(A&&) : " << str
<< endl; }
A &operator=(A &a) {
delete[] str; str = 0;
str = new char[strlen(a.str) + 1];
strcpy(str, a.str);
cout << "A = &A" << endl;
return *this;
}
A &operator=(A &&a) {
delete[] str;
str = a.str; a.str = 0;
cout << "A = &&A" << endl;
return *this;
}
A &&operator+(A &a) {
A b;
b.str = new char[strlen(this->str) + strlen(a.str) + 1];
strcpy(b.str, this->str);
strcpy(b.str + strlen(this->str), a.str);
cout << "A + A = " << b.str << endl;
return std::move(b);
}
const char *operator*() { return str; }
protected:
char *str;
};

int main()
{
A a("Uni");
A b("verse");
A c = a + b;
cout << *c << endl;
cout << *(a+b) << endl;
return 0;
}
------------------
 
Reply With Quote
 
 
 
 
Balog Pal
Guest
Posts: n/a
 
      01-01-2011
"Chameleon" <>

I didn't look into move/&& stuff lately, but this part looks fishy:

> A &&operator+(A &a) {
> A b;
> b.str = new char[strlen(this->str) + strlen(a.str) + 1];
> strcpy(b.str, this->str);
> strcpy(b.str + strlen(this->str), a.str);
> cout << "A + A = " << b.str << endl;
> return std::move(b);
> }


IIRC std::move is nothing but a visible cast from lvalue ref to rvalue ref
without anything extra. What makes this code similar to

A& foo() {A res; return res; }

that returns dongling reference. (one to an object destroyed before a
possible use).

operator + want to return a new object, so make it return A, not A&&, and
let the rest of the system pick up that rvalue in a sensible way.

 
Reply With Quote
 
 
 
 
SG
Guest
Posts: n/a
 
      01-01-2011
On 1 Jan., 14:42, Chameleon <cham_...@hotmail.com> wrote:
>
> class A
> {
> public:
> * * A();
> * * A(const char *string);
> * * ~A();
> * * A(A &a);


The copy constructor usually takes a reference to a CONST.

> * * A && operator+(A &a) {
> * * * * A b;
> * * * b.str = new char[strlen(this->str) + strlen(a.str) + 1];


This this->str as well as a.str could be null pointers couldn't they?

> * * * * strcpy(b.str, this->str);
> * * * * strcpy(b.str + strlen(this->str), a.str);
> * * * * cout << "A + A = " << b.str << endl;
> * * * * return std::move(b);
> * * }


A&& is a reference type. b is a function-local object. You're
returning a reference to a function-local object. This produces a
dangling reference. Using this dangling reference invokes undefined
behaviour. When in doubt, avoid declaring functions that return rvalue
references. This is almost always the wrong thing to do. Your operator
+ should "return an object by value". Also, if you return a function-
local object you should not use std::move as this inhibits a potential
copy/move elision.

Cheers!
SG
 
Reply With Quote
 
Chameleon
Guest
Posts: n/a
 
      01-02-2011
Στις 01/01/2011 22:02, ο/η SG *γραψε:
> On 1 Jan., 14:42, Chameleon<cham_...@hotmail.com> wrote:
>>
>> class A
>> {
>> public:
>> A();
>> A(const char *string);
>> ~A();
>> A(A&a);

>
> The copy constructor usually takes a reference to a CONST.


Yes, Indeed.

>
>> A&& operator+(A&a) {
>> A b;
>> b.str = new char[strlen(this->str) + strlen(a.str) + 1];

>
> This this->str as well as a.str could be null pointers couldn't they?


Of course. But it is a very very super fast sample. So I don't check
every case.

>
>> strcpy(b.str, this->str);
>> strcpy(b.str + strlen(this->str), a.str);
>> cout<< "A + A = "<< b.str<< endl;
>> return std::move(b);
>> }

>
> A&& is a reference type. b is a function-local object. You're
> returning a reference to a function-local object. This produces a
> dangling reference. Using this dangling reference invokes undefined
> behaviour. When in doubt, avoid declaring functions that return rvalue
> references. This is almost always the wrong thing to do. Your operator
> + should "return an object by value". Also, if you return a function-
> local object you should not use std::move as this inhibits a potential
> copy/move elision.
>
> Cheers!
> SG


Thanks a lot!
After 8 years of C++ programming, I realize that return an object by
value, doen't invoke the D'tor of the function-local object.
Whow!!!
This is what I am trying to do, but it exists!.

So, the "&&" needed in case where you must put an object in a
vector<UberObjectClass>. Until now, I used vector<UberObjectClass*>.
Am I right??
 
Reply With Quote
 
SG
Guest
Posts: n/a
 
      01-02-2011
On 2 Jan., 13:59, Chameleon wrote:
> Στις 01/01/2011 22:02, ο/η SG *γραψε:
> > On 1 Jan., 14:42, Chameleon wrote:

>
> >> * * *A&& *operator+(A&a) {
> >> * * * * *A b;
> >> * * * * *b.str = new char[strlen(this->str) + strlen(a.str) + 1];
> >> * * * * *strcpy(b.str, this->str);
> >> * * * * *strcpy(b.str + strlen(this->str), a.str);
> >> * * * * *cout<< *"A + A = "<< *b.str<< *endl;
> >> * * * * *return std::move(b);
> >> * * *}

>
> > A&& *is a reference type. b is a function-local object. You're
> > returning a reference to a function-local object. This produces a
> > dangling reference. Using this dangling reference invokes undefined
> > behaviour. When in doubt, avoid declaring functions that return rvalue
> > references. This is almost always the wrong thing to do. Your operator
> > + should "return an object by value". Also, if you return a function-
> > local object you should not use std::move as this inhibits a potential
> > copy/move elision.

>
> Thanks a lot!
> After 8 years of C++ programming, I realize that return an object by
> value, doen't invoke the D'tor of the function-local object.
> Whow!!!


That depends. If you return by value and write code like this:

A x = ...;
A y = ...;
A z = x + y;

a good compiler is able to elide two unnecessary copies in the third
line. These unnecessary operations are: 1. Copy-constructing the
return value from the function-local object. 2 Copy-constructing z
from the return value. However, the C++ standard doesn't require these
copy elisions. This is optional and a matter of QoI.

The nice thing with the rvalue reference update is that if the
compiler is not able to elide these unnecessary copies (for whatever
reason), it /has/ to use the move constructor if there is one. What
exactly a "move construction" is depends on how you define your move
constructor. Apart from that, there is no magic involved. So, with
another copiler you might still end up with three distinct objects
(function-local, return value, z) but then the move constructor is
used to construct the latter from the former. The only thing you need
to do if you want to enable move semantics is defining a custom move
constructor (and/or move assignment operator). And sometimes you don't
even need to do that because the compiler will generate appropriate
move operations automatically in some cases. Actually, you should
adopt a class design style that minimizes the need for user-defined
copy/move operations.

> So, the "&&" needed in case where you must put an object in a
> vector<UberObjectClass>. Until now, I used vector<UberObjectClass*>.
> Am I right??


Sorry, I don't understand this question. I think you're saying that
with rvalue references and move semantics we are now able to put
"heavy objects" directly into containers instead of storing pointers.
If so, you're right as long as you ÜberObjectClass has a cheap move
constructor. The number of copy/move constructions can be further
reduced by using the new emplace functions (emplace, emplace_back,
etc...).

Cheers!
SG
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Read all of this to understand how it works. then check around on otherRead all of this to understand how it works. then check around on other thelisa martin Computer Support 2 08-18-2005 06:40 AM
Trying to Understand Layer 2 scadav Cisco 6 07-07-2005 05:24 PM
trying to understand postback jim ASP .Net 1 11-22-2004 06:45 PM
Trying to understand ticket/cookie expiration =?Utf-8?B?QmlsbCBCb3Jn?= ASP .Net 0 10-08-2004 10:43 PM
Trying to understand... Paul K ASP .Net 2 11-19-2003 11:39 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57