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 ?
Related
I have a question relevant to move semantics and unique pointer.
Suppose I want to use a manager class to handle a heap allocated integer, and
(1) I delete copy constructor of the manager class to make the handle unique.
(2) The demo function consume is used to takeover ownership of the manager.
I found the following 3 ways all compiled. I was wondering if they all achieve my goal. Are they roughly the same? Any subtle difference? Which is considered as recommended?
(I)
#include <iostream>
#include <memory>
using namespace std;
class intManager {
public:
int* p;
intManager() {
cout << "constructor\n";
p = new int;
}
~intManager() {
cout << "destructor\n";
delete p;
}
intManager(intManager &src) = delete;
intManager(intManager&& src) {
cout << "move constructor\n";
this->p = src.p;
src.p = nullptr;
}
};
void consume(intManager m) {
return;
}
int main() {
intManager m{};
consume(move(m));
return 0;
}
/*
The program prints:
-------------------
constructor
move constructor
destructor
destructor
*/
(II)
#include <iostream>
#include <memory>
using namespace std;
class intManager {
public:
int* p;
intManager() {
cout << "constructor\n";
p = new int;
}
intManager(intManager &src) = delete;
~intManager() {
cout << "destructor\n";
delete p;
}
};
void consume(intManager &&m) {
return;
}
int main() {
intManager m{};
consume(move(m));
return 0;
}
/*
The program prints:
-------------------
constructor
destructor
*/
(III)
#include <iostream>
#include <memory>
using namespace std;
class intManager {
public:
int* p;
intManager() {
cout << "constructor\n";
p = new int;
}
intManager(intManager& src) = delete;
~intManager() {
cout << "destructor\n";
delete p;
}
};
void consume(unique_ptr<intManager> m) {
return;
}
int main() {
unique_ptr<intManager> bar = make_unique<intManager>();
consume(std::move(bar));
return 0;
}
/*
The program prints:
-------------------
constructor
destructor
*/
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.
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";
}
In the code below is implemented a smart pointer that executes fine, but at the end I get the following message:
Here is the code:
smart_ptr.h:
#ifndef SMART_PTR_H
#define SMART_PTR_H
/*
Class: Auto_ptr
It implements a generic
smart pointer that doesn't need
to be deleted explicitly, i.e.
it provides garbage collection.
*/
template<class T>
class Auto_ptr{
public:
// constructors
explicit Auto_ptr(T* p = nullptr): value(p) { }; // constructor
Auto_ptr(Auto_ptr& p); // copy constructor
Auto_ptr& operator= (const Auto_ptr& p); // copy assignment
~Auto_ptr() { std::cout << "pointer deleted\n"; delete value; } // destructor
// access operators
const T& operator* () const { return *value; } // dereference operator
const T* operator->() const { return value; } // indirect class member access (arrow) operator
// non-modifying members
T* get() { return value; } // getter method
void reset(T* v); // reassing new value(default value: nullptr)
T* release(); // transfers the object to another pointer; without destroying it
private:
// data member
T* value;
};
//--------------------------------------------------------------------------------------------------------
// class Auto_ptr member implementations
// Constructors
// copy constructor
template<class T>
Auto_ptr<T>::Auto_ptr(Auto_ptr& p) {
value = p.release();
}
// copy assignment
template<class T>
Auto_ptr<T>& Auto_ptr<T>::operator= (const Auto_ptr& p ) {
if (this == &p) return *this;
if (value) delete value;
value = p.value;
return *this;
}
/*
Function: release()
Use: T ptr = auto_ptr_obj.release();
It transfers the pointer value to the
caller, setting the data member value
to nullptr.
*/
template <class T>
T* Auto_ptr<T>::release() {
T* temp = value;
value = nullptr;
return temp;
}
/*
Function: reset()
Use: auto_ptr_obj.release(new_pointer);
It deletes the object pointer to by
pointer value and assings new_pointer;
*/
template <class T>
void Auto_ptr<T>::reset(T* v) {
delete value;
value = v;
}
#endif
main.cpp:
#include <iostream>
#include "smart_ptr.h"
#include "assert.h"
//=====================================================================
void test1 () {
std::cout <<"\nTest constructor and get() member.\n";
Auto_ptr<int> p(new int);
*p.get() = 5;
std::cout <<"p points to: "<< *p << "\n";
//assert(*p, 5);
std::cout <<"TEST 1 DONE\n";
}
void test2 () {
std::cout <<"\nTest reset() and release() members.\n";
Auto_ptr<int> p(new int);
*p.get() = 5;
std::cout <<"p points to: "<< *p << "\n";
p.reset(new int(10));
std::cout <<"reset() p points to: "<< *p << "\n";
//assert(*p, 10);
int *temp = p.release();
std::cout <<"caller of release(), temp points to: "<< *temp << "\n";
//assert(*temp, 10);
// nullptr dereferece error
// std::cout <<"p after being release()d points to: "<< *p << "\n";
std::cout <<"TEST 2 DONE\n";
}
void test3 () {
std::cout <<"\nTest copy constructor and copy assignment.\n";
Auto_ptr<int> p1(new int(10));
Auto_ptr<int> p2(p1);
std::cout <<"copy constructed p2 points to: "<< *p2 << "\n";
//assert(*p2, 10);
Auto_ptr<int> p3(new int(20));
p1 = p3;
std::cout <<"copy assigned p1 points to: "<< *p1 << "\n";
//assert(*p1, 20);
std::cout <<"TEST 3 DONE\n";
}
//=====================================================================
int main () {
test1 ();
test2 ();
test3 ();
getchar();
}
The interesting note is that in the Live example the error in not reproducible.
What could be the cause of this message ?
This is generally the result of a "double delete" - in this case I suspect it is your copy assignment.
You assign value = p.value; and both copies hold the same value and both attempt to delete it.
You essentially need to move the pointer from one object to the other, as is the case with the copy constructor. You will also need to remove the const as well.
In my constructor I initialize a field. The field is destroyed just after the initialization.
Here's my code and my test:
A.hpp
class A {
private:
T t;
public:
A();
~A();
void add(string name, string num);
};
A.cpp
A::A() {
cout << "Creating A\n";
t = T(100);
cout << "End\n";
}
void A::add(string name, string num) {
cout << "calling add in A\n";
t.add(name, num);
}
T.hpp
class T {
private:
E * t;
public:
T(int size=100);
~T();
void add(std::string name, std::string num);
T.cpp
T::T(int size) : size(size) {
t = new E[size];
}
T::~T() {
cout << "Destroying\n";
// delete[] t; // if I don't comment this I get Segfault when calling add method
}
void T::add(string name, string num){
E e = E(name, num);
t[0] = e;
}
main.cpp
int main(int argc, char* argv[]) {
A a;
a.add("name", "num");
}
Output
Creating A
Destroying
End
calling add in A
Destroying
This code:
t = T(100);
is, equivalently:
T _temp(100);
t = _temp;
Which helps visualize why some T is getting destroyed. It's not your t, it's the temporary T(100). That's why you see two prints of "Destroying"... one for the temporary, and one for A::t.
To avoid the spurious destruction, use an initializer list:
A::A()
: t(100)
{ }