Initially I thought that move constructor will not call the temporary object destructor but when I try it is calling the destructor. So when we steal the data from move constructor I am getting double delete error.
#include <iostream>
using namespace std;
class A
{
public:
A()
: name("default")
{
cout<<"i am default\n";
data = new char[20];
}
A(A&& t)
: name("move")
{
data = t.data;
cout<<"i am move\n";
}
~A()
{
delete data;
cout<<"I am done:"<<name<<endl;
}
char * data;
string name;
};
A getA()
{
A obj;
return obj;
}
int main()
{
A test(std::move(getA()));
}
That's because you are not actually "stealing", you're just copying, and so you'll delete 2 times the same pointer, as you noticed.
To actually "steal" the data, set the original data to nullptr, as it no longer belongs to that object.
A(A&& t)
: name("move")
{
data = t.data;
t.data = nullptr; //'t' doesn't own its data anymore
cout<<"i am move\n";
}
You could also use std::swap (thanks #RemyLebeau):
A(A&& t) : name("move"), data(nullptr)
{
std::swap(data, t.data);
cout << "i am move\n";
}
Related
#include <iostream>
#include <string>
using namespace std;
class Class1 {
string s;
public:
Class1(const string& s_) : s(s_) {}
};
class Class2 {
string s;
public:
Class2(string s_) : s(std::move(s_)) {}
};
class Class3 {
string s;
public:
Class3(string s_) : s(s_) {}
};
int main()
{
string str = "ABC";
Class1 a(str);
Class2 b(str);
Class3 c(str);
}
I'm trying to find the cost of my constructor.
Class 1: cost 1 copy constructor
Class 2: cost 1 copy constructor and 1 move constructor
Class 3: cost 1 copy constructor + {A. nothing, B. move constructor, C. copy constructor}
Is the compiler smart enough to copy str directly into c.s ? What is the answer for the 3rd case?
Big edit: using a vector-like class, the answer is C. But is there any reason why the compiler can't steal s_ even when the object will be destructed after s(s_) ?
#include <iostream>
#include <string>
using namespace std;
template <typename T = int>
class MyVector {
private:
int n;
T* data;
public:
MyVector() {
n = 0;
data = nullptr;
cout << "MyVector default constructor\n";
}
MyVector(int _n) {
n = _n;
data = new T[n];
cout << "MyVector param constructor\n";
}
MyVector(const MyVector& other) {
n = other.n;
data = new T[n];
for (int i=0; i<n; i++) data[i] = other.data[i];
cout << "MyVector copy constructor\n";
}
MyVector(MyVector&& other) {
n = other.n;
data = other.data;
other.n = 0;
other.data = nullptr;
cout << "MyVector move constructor\n";
}
MyVector& operator = (const MyVector& other) {
if (this != &other) {
n = other.n;
delete[] data;
data = new T[n];
for (int i=0; i<n; i++) data[i] = other.data[i];
}
cout << "MyVector copy assigment\n";
return *this;
}
MyVector& operator = (MyVector&& other) {
if (this != &other) {
n = other.n;
delete[] data;
data = other.data;
other.n = 0;
other.data = nullptr;
}
cout << "MyVector move assigment\n";
return *this;
}
~MyVector() {
delete[] data;
cout << "MyVector destructor: size = " << n << "\n";
}
int size() {
return n;
}
};
class Class1 {
MyVector<> s;
public:
Class1(const MyVector<>& s_) : s(s_) {}
};
class Class2 {
MyVector<> s;
public:
Class2(MyVector<> s_) : s(std::move(s_)) {}
};
class Class3 {
MyVector<> s;
public:
Class3(MyVector<> s_) : s(s_) {}
};
int main()
{
MyVector<> vec(5);
cout << "-----------\n";
cout << "Class1\n";
Class1 a(vec);
cout << "\n------------\n";
cout << "Class3\n";
Class2 b(vec);
cout << "\n------------\n";
cout << "Class3\n";
Class3 c(vec);
cout << "\n------------\n";
return 0;
}
s_ is a lvalue in the initializer s(s_). So the copy constructor will be used to construct s. There is not automatic move like e.g. in return statements. The compiler is not allowed to elide this constructor call.
Of course a compiler can always optimize a program in whatever way it wants as long as observable behavior is unchanged. Since you cannot observe copies of a string being made if you don't take addresses of the string objects, the compiler is free to optimize the copies away in any case.
If you take a constructor argument to be stored in a member by-value, there is no reason not to use std::move.
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);
}
};
I created ABC class and created its three objects by normal, assign and copy constructor. Now they are use same memory address for ptr.
When these objects are deleted means coming out of scope then first object deleted, but for second it is give error that memory is already deleted.
This is fine. that I understand.
#include<iostream>
using namespace std;
class ABC
{
private:
int a;
int *ptr;
public:
ABC(); // Simple constructor.
ABC(int a, int b); // Parameterized constructor.
ABC(const ABC &obj); // Copy constructor.
~ABC(); // Destructor.
void display(); // Display.
ABC& operator=(const ABC &obj); // Operator Overload.
};
ABC::ABC()
{
}
ABC::ABC(int a, int b)
{
cout << "Parameterized constructor" << endl;
// allocate memory for the pointer;
this->a = a;
ptr = new int;
ptr = &b;
}
ABC::ABC(const ABC &obj)
{
cout << "Copy constructor" << endl;
a = obj.a;
//ptr = new int;
//*ptr = *obj.ptr; // copy the value
ptr = obj.ptr;
}
ABC& ABC :: operator=(const ABC &obj)
{
cout <<"Assignemnt operator overload"<<endl;
this->a = obj.a;
this->ptr = obj.ptr;
return *this;
}
ABC::~ABC(void)
{
cout << "Freeing memory!" << endl;
delete ptr;
}
void ABC::display() {
cout << "a value = : " << a <<endl;
cout << "ptr value = : " << ptr <<endl;
cout << "*ptr value = : " << *ptr <<endl;
}
int main()
{
// Normal.
ABC obj1(1, 2);
cout << "Point Obj1 value = : "<<endl;
obj1.display();
cout<<"\n\n";
// Assignment.
ABC obj2;
obj2 = obj1;
cout << "Point Obj2 value = : "<<endl;
obj2.display();
cout<<"\n\n";
// Copy constructor.
ABC obj3(obj1);
cout << "Point Obj3 value = : "<<endl;
obj3.display();
return 0;
}
What I want to do it that, I do not want to delete memory when other objects are using. How to handle this by Smart Pointer, I not want to do by in-build sheared pointer. I want to write Smart Pointer class and increase ptr reference count when other objects use same memory. But do not know how to do.
class SmartPointer
{
public:
int *ptr;
int ref;
SmartPointer();
SmartPointer(int *p);
int& operator *();
~SmartPointer();
};
SmartPointer::SmartPointer()
{
cout<<"SmartPointerInitilaize default"<<endl;
ref = 1;
}
SmartPointer::SmartPointer(int *p)
{
cout<<"SmartPointerInitilaize para"<<endl;
ptr = p;
ref = 1;
}
int& SmartPointer:: operator *()
{
return *ptr;
}
SmartPointer::~SmartPointer()
{
cout<<"SmartPointer De-Initilaize"<<endl;
//delete ptr;
}
What you basically want to do is to implement a std::shared_ptr. You shouldn't do it normally, because it is quite tricky, however for educational purposes and to understand how that works:
1) The ref count needs to be part of the pointer data passed around (if not static), shared by all the "linked" SmartPointer instances.
2) You still need to define the copy constructor/assignment operator to increase the reference count. And in the destructor you decrease the refcount, and if zero, delete the pointer (and the extra data).
An example:
class SmartPointer
{
struct Data {
Data(int *p)
: ptr(p)
, ref(1)
{}
~Data() {Release();}
void Acquire() {
++ref;
}
void Release() {
if (!--ref) { delete ptr; delete this; }
}
int *ptr;
int ref;
};
Data *data;
public:
SmartPointer()
: data(new Data(NULL))
{}
SmartPointer(int *p)
: data(new Data(p))
{}
SmartPointer(const SmartPointer& x)
: data(x.data)
{ data->Acquire(); }
SmartPointer& operator =(const SmartPointer& x)
{
if (this != &x) {
data->Release();
data = x.data;
data->Acquire();
}
}
int& operator *() { return *data->ptr; }
~SmartPointer() { data->Release(); }
};
Note that this is very simplified (e.g. not thread safe), just the basic idea.
The actual std or boost shared_ptr is much more complicated (templated, supports custom deleter which involves type erasure etc.).
Add shared_level integer in SmartPointer
class SmartPointer{
public:
int *ptr;
int ref;
int shared_level;
SmartPointer();
SmartPointer(int *p);
int& operator *();
~SmartPointer();
};
Whenever the abc constructor is calling. Increment shared_level by 1. When ever deconstructor calls, Decrement it by 1.
And While deconstructing check for SmartPointer->shared_level value, And if it is 1. Delete pointer, else just decrements is enough.
Note : Better use locks for sharePointer, If u want to access in multiple threads.
I want to create member variable sptr of ABC which is object of other class SmartPointer. And then assign value to that member variable.
#include<stdio.h>
#include<iostream>
using namespace std;
class SmartPointer
{
private:
int *ptr;
public:
SmartPointer(int *p);
int& operator *();
~SmartPointer();
};
SmartPointer::SmartPointer(int *p = NULL)
{
cout<<"Initilaize SmartPointer"<<p<< endl;
ptr = p;
}
int& SmartPointer:: operator *()
{
return *ptr;
}
SmartPointer::~SmartPointer()
{
cout<<"De-Initilaize SmartPointer"<<endl;
delete ptr;
}
class ABC
{
private:
int a;
SmartPointer *sptr;
int ref;
public:
ABC(); // Simple constructor.
ABC(int a, int b); // Parameterized constructor.
// ABC(const ABC &obj); // Copy constructor.
~ABC(); // Destructor.
void display(); // Display.
// ABC& operator=(const ABC &obj); // Operator Overload.
};
ABC::ABC()
{
ref= 1;
}
ABC::ABC(int a, int b)
{
cout << "Parameterized constructor input" << endl;
// allocate memory for the pointer;
sptr = new SmartPointer(&a);
cout << "Parameterized constructor Out"<<sptr << endl;
}
ABC::~ABC(void)
{
cout << "Freeing memory!" << endl;
ref --;
if(ref==0)
{
//delete sptr;
}
}
void ABC::display()
{
}
int main()
{
// int a = 10;
// SmartPointer obj1(&a);
// Normal.
ABC obj2(1, 2);
return 0;
}
created sptr = new SmartPointer(&a);, but how to get value of sptr ?
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.