Re: Can a temporary be assigned to itself?

Discussion in 'C++' started by Howard Hinnant, Mar 22, 2013.

  1. On Mar 22, 5:05 am, Juha Nieminen <> wrote:
    > If you are implementing the regular operator=() for a class, you (usually)
    > need to take into account the special case that the same object is being
    > assigned to itself. (If you don't, you may end up deleting the managed
    > resource when you shouldn't.)
    >
    > However, is the same true for the operator=() taking an rvalue reference?
    > Do you have to take into account the possibility that the object may be
    > assigned to itself?


    An object can be self-move-assigned. The operation does not need to
    be a no-op, like the self-copy-assignment case. It simply needs to
    not corrupt the object.


    #include <iostream>
    #include <algorithm>

    class A
    {
    int* data_;
    public:
    A(int data = 0) : data_(new int(data)) {}
    ~A() {delete data_;}
    A(A&& a) : data_(a.data_) {a.data_ = nullptr;}
    A& operator=(A&& a)
    {
    // dump existing resources
    delete data_;
    // put lhs in valid state
    data_ = nullptr;
    // Move resources
    data_ = a.data_;
    // put rhs in valid state
    a.data_ = nullptr;
    return *this;
    }

    friend std::eek:stream&
    operator<<(std::eek:stream& os, const A& a)
    {
    if (a.data_ != nullptr)
    os << "A = " << *a.data_;
    else
    os << "A = null";
    return os;
    }
    };

    int main()
    {
    A a1(1);
    std::cout << a1 << '\n';
    std::cout << "self swap:\n";
    std::swap(a1, a1);
    std::cout << a1 << '\n';
    std::cout << "self move assignment:\n";
    a1 = std::move(a1);
    std::cout << a1 << '\n';
    }

    A = 1
    self swap:
    A = 1
    self move assignment:
    A = null
    Howard Hinnant, Mar 22, 2013
    #1
    1. Advertising

  2. Howard Hinnant

    Öö Tiib Guest

    On Friday, 22 March 2013 18:22:09 UTC+2, Howard Hinnant wrote:
    > On Mar 22, 5:05 am, Juha Nieminen <> wrote:
    > > If you are implementing the regular operator=() for a class, you (usually)
    > > need to take into account the special case that the same object is being
    > > assigned to itself. (If you don't, you may end up deleting the managed
    > > resource when you shouldn't.)
    > >
    > > However, is the same true for the operator=() taking an rvalue reference?
    > > Do you have to take into account the possibility that the object may be
    > > assigned to itself?

    >
    > An object can be self-move-assigned. The operation does not need to
    > be a no-op, like the self-copy-assignment case. It simply needs to
    > not corrupt the object.


    ....

    > A = 1
    >
    > self swap:
    >
    > A = 1
    >
    > self move assignment:
    >
    > A = null


    Isn't that quite annoying to some? Legally fine but I suspect that I would
    love a guaranteed crash during self-assignment slightly more.
    Öö Tiib, Mar 22, 2013
    #2
    1. Advertising

  3. On Mar 22, 12:59 pm, Öö Tiib <> wrote:
    >
    > Isn't that quite annoying to some? Legally fine but I suspect that I would
    > love a guaranteed crash during self-assignment slightly more.


    I have sometimes suggested that people put assert(this != &other) in
    their move assignment operators to actively detect self-move-
    assignment and treat it as a performance bug.

    If you do that, and you detect that is code I wrote that is causing
    you to self-move-assign, I would appreciate a bug report and I will
    get it fixed. That being said, if it is your code that is doing a
    self-swap, causing std::swap to self-move-assign, I will push it back
    to you to fix the self-swap. :)

    PS: "You" here refers to everyone that might be a client of code I
    write, e.g. libc++.
    Howard Hinnant, Mar 22, 2013
    #3
  4. Howard Hinnant

    Öö Tiib Guest

    On Friday, 22 March 2013 19:10:06 UTC+2, Howard Hinnant wrote:
    > On Mar 22, 12:59 pm, Öö Tiib <> wrote:
    > > Isn't that quite annoying to some? Legally fine but I suspect that I would
    > > love a guaranteed crash during self-assignment slightly more.

    >
    > I have sometimes suggested that people put assert(this != &other) in
    > their move assignment operators to actively detect self-move-
    > assignment and treat it as a performance bug.


    I prefer to log/trace it in debug builds. Performance defects do
    not deserve harsher punishments.

    > If you do that, and you detect that is code I wrote that is causing
    > you to self-move-assign, I would appreciate a bug report and I will
    > get it fixed. That being said, if it is your code that is doing a
    > self-swap, causing std::swap to self-move-assign, I will push it back
    > to you to fix the self-swap. :)


    On the case with swap ... "Effects: Exchanges values stored in two
    locations." That implicitly means that the effect is undefined if the
    values are not in two locations and so I feel that I have no true right
    to complain, only to pout a bit. :-/

    > PS: "You" here refers to everyone that might be a client of code I
    > write, e.g. libc++.


    Yes! You are in admirable situation. I trust that your 'swap(a,a)'
    actually does work nicely and the effect is what the intuition tells
    not the horrors what happen when standard "does not tell". ;-)
    Öö Tiib, Mar 22, 2013
    #4
  5. Öö Tiibæ–¼ 2013å¹´3月23日星期六UTC+8上åˆ12時59分31秒寫é“:
    > On Friday, 22 March 2013 18:22:09 UTC+2, Howard Hinnant wrote:
    >
    > > On Mar 22, 5:05 am, Juha Nieminen <> wrote:

    >
    > > > If you are implementing the regular operator=() for a class, you (usually)

    >
    > > > need to take into account the special case that the same object is being

    >
    > > > assigned to itself. (If you don't, you may end up deleting the managed

    >
    > > > resource when you shouldn't.)

    >
    > > >

    >
    > > > However, is the same true for the operator=() taking an rvalue reference?

    >
    > > > Do you have to take into account the possibility that the object may be

    >
    > > > assigned to itself?

    >
    > >

    >
    > > An object can be self-move-assigned. The operation does not need to

    >
    > > be a no-op, like the self-copy-assignment case. It simply needs to

    >
    > > not corrupt the object.

    >
    >
    >
    > ...
    >
    >
    >
    > > A = 1

    >
    > >

    >
    > > self swap:

    >
    > >

    >
    > > A = 1

    >
    > >

    >
    > > self move assignment:

    >
    > >

    >
    > > A = null

    >
    >
    >
    > Isn't that quite annoying to some? Legally fine but I suspect that I would
    >
    > love a guaranteed crash during self-assignment slightly more.


    Well, I give a simple example used in c/c++ to illustrate
    the unsafe part of c/c++.

    int mcopy( char *p, char *q, int n)

    {
    //
    if n==0 return 0; // nothing to do
    if n<0 return -1; // failed
    // if p and q are overlapped what will happen ???
    // caller responsible version

    while(n--) {*p++=*q++;}
    return 0; // OK
    }
    88888 Dihedral, Mar 22, 2013
    #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. Replies:
    7
    Views:
    3,178
    James Kanze
    Feb 12, 2008
  2. Öö Tiib
    Replies:
    2
    Views:
    189
    Öö Tiib
    Mar 22, 2013
  3. James Kanze
    Replies:
    15
    Views:
    298
    Öö Tiib
    Mar 24, 2013
  4. Krishnan Shankar

    List getting extended when assigned to itself

    Krishnan Shankar, Aug 25, 2013, in forum: Python
    Replies:
    1
    Views:
    96
    Steven D'Aprano
    Aug 25, 2013
  5. Benjamin Kaplan
    Replies:
    0
    Views:
    87
    Benjamin Kaplan
    Aug 25, 2013
Loading...

Share This Page