2

I have a class A where, the copy assignment operator is deleted. How should I swap two instances of A ?

I tried using std::swap but that did not work.

class A {
private:
    int a;
public:
    A& operator=(const A& other) = delete;
    A(int _a = 0):a(_a){}
    void showA() { std::cout << a << std::endl; }
};

int main()
{
    A obj1(10);
    A obj2(20);
    obj1.showA();
    obj2.showA();
    //A temp;
    //temp = obj1;
    //obj1 = obj2;
    //obj2 = temp;
    obj1.showA();
    obj2.showA();
}

I expect obj1 and obj2 to be swapped. Initially obj1.a is 10 and obj2.a is 20, I expect obj1.a to be 20 and obj2.ato be 10 when done.

rranjik
  • 690
  • 9
  • 21
  • 1
    You can overload `swap`. – molbdnilo Feb 09 '19 at 21:30
  • 2
    If there's no public interface for modifying `a` then you can't swap two objects without modifying the class itself. – Kevin Feb 09 '19 at 21:34
  • 2
    `std::swap` doesn't require copy assignment operator, but it requires move constructor and move assignment operator. Since copy assignment is declared (as deleted), move constructors are no longer implicitly defined and should be declared explicitly (e.g. with `default` keyword). – Yksisarvinen Feb 09 '19 at 21:36
  • @molbdnilo That would require modifying the class, wouldn't it ? – rranjik Feb 09 '19 at 21:36
  • 1
    @rranjik: The crux of the problem is that the `A` class is immutable. So no, there's no way to swap values. You have to swap the entire instance, which is tricky to do on the stack. See `std::optional`. – Mooing Duck Feb 09 '19 at 21:53
  • @MooingDuck,@Kevin Thanks! – rranjik Feb 09 '19 at 22:47

1 Answers1

3

As @Yksisarvinen indicated you need to have move constructor and move assignment defined in order to get std::move to work:

#include <iostream>
#include <utility> 

class A {
private:
    int a;
public:
    A(int a_) : a(a_) {}
    A(const A& other) = delete;
    A& operator=(const A&) = delete;
    A(A&& other) { 
        a = other.a;
    }
    A& operator=(A&& other) { 
        a = other.a;
        return *this;
    }
    void showA() { std::cout << a << std::endl; }
};

int main(int argc, char* argv[]) {
    A obj1(10);
    A obj2(20);
    obj1.showA();
    obj2.showA();

    std::swap(obj1, obj2);
    std::cout << "swapped:" << std::endl;
    obj1.showA();
    obj2.showA();
    return 0;
}
rranjik
  • 690
  • 9
  • 21
Hwy2Hell
  • 80
  • 1
  • 9
  • 3
    Great one ! To avoid some unnecessary typing and later maintenance, I'd suggest to define the move constructor and move assignment as default (see https://ideone.com/gfKvBO) – Christophe Feb 09 '19 at 22:47