How to swap two objects without copy assignment operator? - c++

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.

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;
}

Related

doing deep copy vector of pointers in copy constructor got both vector member changed?

i need deep copy in my project and for now i memcpy the srcObj into destObj then
if destObj owns pointer members, i just create all the obj and do this method recursively
here's the pseudo:
class B
{
public:
B(int id_) : id(id_) {};
int id = 0;
};
class A
{
public:
vector<B*> vecInt;
B objB = 111;
A()
{
vecInt.push_back(new B(1));
vecInt.push_back(new B(2));
vecInt.push_back(new B(3));
}
A(const A& rhs)
{
memcpy(this, &rhs, sizeof(A));
for (auto i = 0; i < rhs.vecInt.size(); i++)
{
auto ptrTmp = new B(rhs.vecInt[i]->id);
cout << "00000000000 " << rhs.vecInt[i] << endl;;
this->vecInt[i] = ptrTmp;
cout << "11111111111 " << ptrTmp << endl;;
cout << "22222222222 " << rhs.vecInt[i] << endl;;
}
}
};
here's the issue, every time i assign this->vecInt[i] within the loop, the rhs.vecInt[i] changes too and they both indicate to one address, i have no idea why this happened.
appreciate any help.
The memcpy() is absolutely wrong and needs to be removed. It is corrupting your A object’s data members. It may work for the objB member, but definitely not the vecInt member.
But, even with thae memcpy() removed, you would still have undefined behavior as you are trying to assign to vector elements that don’t exist yet. To deep-copy a vector of pointers, you have no choice but to clone each dynamic B object one at a time and add it to the new vector.
The correct way to implement your copy constructor should look more like this instead:
A(const A& rhs) : objB(rhs.objB)
{
vecInt.reserve(rhs.vecInt.size());
for (auto *elem : rhs.vecInt)
{
vecInt.push_back(new B(*elem));
}
}
You also need to add a destructor, move constructor, copy assignment operator, and move assignment operator, per the Rule of 3/5/0:
class A
{
public:
vector<B*> vecInt;
B objB = 111;
A()
{
vecInt.push_back(new B(1));
vecInt.push_back(new B(2));
vecInt.push_back(new B(3));
}
A(const A& rhs) : objB(rhs.objB)
{
vecInt.reserve(rhs.vecInt.size());
for (auto *elem : rhs.vecInt)
{
vecInt.push_back(new B(*elem));
}
}
A(A&& rhs) : vecInt(move(rhs.vecInt)), objB(move(rhs.objB)) {}
~A()
{
for(auto *elem : vecInt)
delete elem;
}
A& operator=(A rhs)
{
vecInt.swap(rhs.vecInt);
objB.id = rhs.objB.id;
return *this;
}
};
That being said, consider using std::vector<std::unique_ptr<B>> instead of std::vector<B*>. That will eliminate the need for an explicit destructor. Don’t use new/delete in modern C++ if you can avoid it.
class A
{
public:
vector<unique_ptr<B>> vecInt;
B objB = 111;
A()
{
vecInt.push_back(make_unique<B>(1));
vecInt.push_back(make_unique<B>(2));
vecInt.push_back(make_unique<B>(3));
}
A(const A& rhs) : objB(rhs.objB)
{
vecInt.reserve(rhs.vecInt.size());
for (auto &elem : rhs.vecInt)
{
vecInt.push_back(make_unique<B>(*elem));
}
}
A(A&& rhs) : vecInt(move(rhs.vecInt)), objB(move(rhs.objB)) {}
~A() = default;
A& operator=(A rhs)
{
vecInt.swap(rhs.vecInt);
objB.id = rhs.objB.id;
return *this;
}
};
Even better, just use std::vector<B> instead, and let the compiler handle everything else for you:
class A
{
public:
vector<B> vecInt;
B objB = 111;
A()
{
vecInt.emplace_back(1);
vecInt.emplace_back(2);
vecInt.emplace_back(3);
}
};

c++ : move assignement operator and inheritance

This code compiles and runs fine:
#include <iostream>
class Base
{
public:
Base(int value)
: clean_(true)
{
value_ = new int;
*value_ = value;
}
~Base()
{
if(clean_)
delete value_;
}
Base(Base&& other) noexcept
: value_{std::move(other.value_)},
clean_(true)
{
other.clean_=false;
}
Base& operator=(Base&& other) noexcept
{
value_ = std::move(other.value_);
other.clean_=false;
clean_=true;
}
void print()
{
std::cout << value_ << " : " << *value_ << std::endl;
}
int* value_;
bool clean_;
};
class A : public Base
{
public:
A(int v1, double v2) : Base(v1)
{
a_ = new double;
*a_ = v2;
}
A(A&& other) noexcept
: Base(std::forward<Base>(other)),
a_(std::move(other.a_))
{}
A& operator=(A&& other) noexcept
{
// should not the move assignment operator
// of Base be called instead ?
// If so: how ?
this->value_ = std::move(other.value_);
other.clean_=false;
this->clean_=true;
a_ = std::move(other.a_);
}
void print()
{
std::cout << this->value_ << " "
<< *(this->value_) << " "
<< a_ << " " << *a_ << std::endl;
}
double* a_;
bool clean_;
};
A create_a(int v1,double v2)
{
A a(v1,v2);
return a;
}
int main()
{
Base b1(20);
b1.print();
Base b2 = std::move(b1);
b2.print();
A a1(10,50.2);
a1.print();
A a2 = std::move(a1);
a2.print();
A a3 = create_a(1,2);
a3.print();
}
A is a subclass of Base.
The code of the move assignment operator of A replicates the one of Base.
Is there a way to avoid this replication of code ?
Change int* value_; to int value_; and double* a_; to double a_; and you no longer need to write any of the special member functions as the compiler provided defaults Just Work™
If you really need dynamic memory allocation, then use a RAII type like std::vector, std::unique_ptr, std::shared_ptr, ect. in its place since they are designed to be copied and or moved correctly.

Why is the constructor with rvalue reference not being used or ignored?

For the code below, I would expect the standard output to be a empty default constructed string.
How is the actual output of a.get() the string if all means to modify m_x through the constructor are disabled in this fashion?
#include <iostream>
#include <string>
class Test {
public:
Test() = delete;
explicit Test(const std::string& x) { m_x = x; }
explicit Test(const Test&) = delete;
explicit Test(Test&& rhs) { }
Test& operator=(const Test&) = delete;
Test& operator=(Test&&) = delete;
std::string get() const { return m_x; }
private:
std::string m_x;
};
int main(int argc, char** argv)
{
auto a(Test("tetst"));
std::cout << a.get() << std::endl;
return 0;
}

How to enforce a calling of a moving constructor (C++)?

I have this couple of code-lines:
#include <iostream>
using namespace std;
class A
{
public:
A() noexcept
{
cout << "A::A()" << endl;
}
A(const A&) noexcept
{
cout << "A::A(const A&)" << endl;
}
A(A&&) noexcept
{
cout << "A::A(A&&)" << endl;
}
};
class B
{
public:
B(const A& a) noexcept :
_a(a)
{}
B(A&& a) noexcept :
_a(a)
{}
private:
A _a;
};
int main(int argc, char* argv[])
{
A a;
B b1 = B(a);
B b2 = B(A());
}
They produce this output:
A::A()
A::A(const A&)
A::A()
A::A(const A&)
What need I to do in order to the A::A(A&&) will be called from the B::B(A&&)?
As you can see adding noexcept does not solve this issue.
Although the type of a is an rvalue reference to A, a itself is an lvalue. To retain its rvalue-ness, you need to use std::move:
B(A&& a) noexcept :
_a(std::move(a))
{}

Move constructor and non-const copy constructor

I am new in move constructor, I surveyed from some sites and tried using the Visual Studio 11 Express Beta..
Below is my testing code...
#include <iostream>
using namespace std;
class Foo
{
public:
Foo()
: Memory(nullptr)
{
cout<<"Foo Constructor"<<endl;
}
~Foo()
{
cout<<"~Foo Destructor"<<endl;
if(Memory != nullptr)
delete []Memory;
}
Foo(Foo& rhs)
: Memory(nullptr)
{
cout<<"Copy Constructor"<<endl;
//allocate
//this->Memory = new ....
//copy
//memcpy(this->Memory, rhs.Memory...);
}
Foo& operator=(Foo& rhs)
{
cout<<"="<<endl;
}
void* Memory;
Foo(int nBytes) { Memory = new char[nBytes]; }
Foo(Foo&& rhs)
{
cout<<"Foo Move Constructor"<<endl;
Memory = rhs.Memory;
rhs.Memory = nullptr;
}
};
Foo Get()
{
Foo f;
return f;
//return Foo();
}
void Set(Foo rhs)
{
Foo obj(rhs);
}
int main()
{
Set(Get());
return 0;
}
I don't know why it will not enter move constructor.
It's really a Rvalue from Get();
If I modified non-const copy constructor from const constructor,
it will enter move constructor. Behavior changed...
Could anyone kindly explain why it happened?
#include <iostream>
using namespace std;
class Foo
{
public:
Foo():
Memory(nullptr)
{
cout<< this << "Foo Constructor"<<endl;
}
~Foo()
{
cout<< this << "~Foo Destructor"<<endl;
if(Memory != nullptr)
delete []Memory;
}
Foo(Foo& rhs)
:Memory(nullptr)
{
cout<<this << "Copy Constructor"<<endl;
//allocate
//this->Memory = new ....
//copy
//memcpy(this->Memory, rhs.Memory...);
}
Foo& operator=(Foo& rhs)
{
cout<<"="<<endl;
}
void* Memory;
Foo(int nBytes) { Memory = new char[nBytes]; }
Foo(Foo&& rhs)
{
cout<<this << "Foo Move Constructor"<<endl;
Memory = rhs.Memory;
rhs.Memory = nullptr;
}
};
Foo Get()
{
Foo f;
cout << &f << "f" <<endl;
return f;
}
void Set(Foo rhs)
{
Foo obj(rhs);
cout << &obj << "obj"<<endl;
}
int main()
{
Set(Get());
return 0;
}
output...
0x7fffe38fa0a0 Foo Constructor
0x7fffe38fa0a0 f
0x7fffe38fa070 Copy Constructor
0x7fffe38fa070 obj
0x7fffe38fa070 ~Foo Destructor
0x7fffe38fa0a0 ~Foo Destructor
Answer: Due to the Named Return Value Optimization the parameter rhs is constructed inplace as an alias of local variable f. (That is to say rhs and f are the same instance).
As rhs is an lvalue, the copy constructor is used to copy construct obj from rhs.