Trying to understand "&&"

Discussion in 'C++' started by Chameleon, Jan 1, 2011.

  1. Chameleon

    Chameleon Guest

    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;
    }
    ------------------
    Chameleon, Jan 1, 2011
    #1
    1. Advertising

  2. Chameleon

    Balog Pal Guest

    "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.
    Balog Pal, Jan 1, 2011
    #2
    1. Advertising

  3. Chameleon

    SG Guest

    On 1 Jan., 14:42, Chameleon <> 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
    SG, Jan 1, 2011
    #3
  4. Chameleon

    Chameleon Guest

    Στις 01/01/2011 22:02, ο/η SG έγÏαψε:
    > On 1 Jan., 14:42, Chameleon<> 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??
    Chameleon, Jan 2, 2011
    #4
  5. Chameleon

    SG Guest

    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
    SG, Jan 2, 2011
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Paul K

    Trying to understand...

    Paul K, Nov 19, 2003, in forum: ASP .Net
    Replies:
    2
    Views:
    346
    Paul K
    Nov 19, 2003
  2. =?Utf-8?B?QmlsbCBCb3Jn?=

    Trying to understand ticket/cookie expiration

    =?Utf-8?B?QmlsbCBCb3Jn?=, Oct 8, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    356
    =?Utf-8?B?QmlsbCBCb3Jn?=
    Oct 8, 2004
  3. jim

    trying to understand postback

    jim, Nov 22, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    371
    =?Utf-8?B?Sm9lbCBDYWRl?=
    Nov 22, 2004
  4. elektrophyte

    Trying to understand Tomcat logging

    elektrophyte, Oct 5, 2005, in forum: Java
    Replies:
    0
    Views:
    1,173
    elektrophyte
    Oct 5, 2005
  5. Jimi Hullegård

    Re: Trying to understand Tomcat logging

    Jimi Hullegård, Oct 6, 2005, in forum: Java
    Replies:
    0
    Views:
    422
    Jimi Hullegård
    Oct 6, 2005
Loading...

Share This Page