Is this a smart pointer? - c++

Please have a look at the code below. Is this a smart pointer?
If so, why the first object, p1, is dangling at the end of the code? (That is p2 is deleted by the destructor but p1 remains, why?)
#include <iostream>
#include <vector>
using namespace std;
template <class T> class my_auto_ptr {
T* myptr;
public:
my_auto_ptr(T* ptr = 0) : myptr(ptr) { }
~my_auto_ptr() {
delete myptr;
}
T* operator ->() const {
if (myptr != nullptr) return myptr;
else throw runtime_error("");
}
T& operator* () const {
if (myptr != nullptr) return *myptr;
else throw runtime_error("");
}
T* release() {
T* rptr = myptr;
myptr = 0;
return rptr;
}
};
//----------------------------------
int main() try {
my_auto_ptr<vector<int> > p1(new vector<int>(4, 5));
cout << p1->size() << endl;
my_auto_ptr<int> p2(new int(6));
cout << *p2 << endl;
return 0;
}
//-------------------------------
catch (...) {
cerr << "Exception occurred.\n";
return 1;
}

Is this a smart pointer?
No. It is copyable and assignable, but performing either of those operations will result in multiple deletes. You need to make sure that it is either non-copyable and non-assignable, or that it implements the rule of 3 or 5.

Related

Self/own implementation of smart pointers

I'm trying to code my own implementation of shared pointers (for fun/challenge) but I hit a dead end after I cannot make the constructor accept any (auto) type of pointer variable. The problem is, for now I can only make my own smart pointer points to a certain data-type (class P) but I want it to be able to point to any data type however the problem is I need to specify the data type in the constructor arguments.
Code:
#include <iostream>
#include <memory>
class P //dummy class
{
int x;
public:
P() : x(42) {}
~P() {}
void print()
{
std::cout<<"Address = "<< this << "\n";
}
};
class P2 //dummy class 2
{
public:
P2() {}
~P2() {}
void print()
{
std::cout<<"Address = "<< this << "\n";
}
};
class SmartP
{
P *ptr;
public:
SmartP(P *p) : ptr(p) {}
~SmartP()
{
delete ptr;
}
P& operator* ()
{
return *ptr;
}
P* operator-> ()
{
return ptr;
}
};
void rawPointer()
{
P *p(new P);
p->print();
delete p; //when removed, next allocated address will be different
}
void smartPointerOwn()
{
SmartP spo(SmartP(new P));
//This should also work but currently it does not: SmartP spo(SmartP(new P2));
spo->print();
//Do not need a delete
}
void smartPointer()
{
std::unique_ptr<P> sp(new P);
sp->print();
//Do not need a delete
}
int main()
{
rawPointer();
smartPointerOwn();
smartPointer();
std::cin.get(); //Prevent exiting console prematurely
return 0;
}
Thanks!
here some basic example to help start you off. Like already mentioned in the comments you should first check some existing smart pointer implementations.
This example is very incomplete - for ex. the reference counting is missing (if shared pointer wanted). But it gives you an idea. I hope it helps a little bit.
#include <iostream>
using namespace std;
template <typename T>
class SmartP {
public:
SmartP() : p{nullptr} {}
SmartP(T* pp) : p{pp} {}
~SmartP() { delete p; }
// dereferencing operators
friend T& operator*(const SmartP<T>& sp) { return *(sp.p); }
T& operator->() const { return *p; }
// get the raw pointer
T* get() const { return p; }
private:
T* p;
};
int main() {
SmartP<int> p{new int{3}};
cout << *p << endl;
*p = 4;
cout << *p << endl;
}

Do not delete ptr when momery is used by other objects

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.

Visual C++ Debug Assertion Failed?

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.

Ref counted smart pointer's assignment operator

despite the ocean of smart pointer questions out there, I seem to be stuck with one more. I am trying to implement a ref counted smart pointer, but when I try it in the following case, the ref count is wrong. The comments are what I think should be the correct ref counts.
Sptr<B> bp1(new B); // obj1: ref count = 1
Sptr<B> bp2 = bp1; // obj1: ref count = 2
bp2 = new B; // obj1: ref count = 1, obj2: rec count = 1 **problem**
In my implementation, my obj2 ref count is 2, because of this code:
protected:
void retain() {
++(*_rc);
std::cout << "retained, rc: " << *_rc << std::endl;
}
void release() {
--(*_rc);
std::cout << "released, rc: " << *_rc << std::endl;
if (*_rc == 0) {
std::cout << "rc = 0, deleting obj" << std::endl;
delete _ptr;
_ptr = 0;
delete _rc;
_rc = 0;
}
}
private:
T *_ptr;
int *_rc;
// Delegate private copy constructor
template <typename U>
Sptr(const Sptr<U> *p) : _ptr(p->get()), _rc(p->rc()) {
if (p->get() != 0) retain();
}
// Delegate private assignment operator
template <typename U>
Sptr<T> &operator=(const Sptr<U> *p) {
if (_ptr != 0) release();
_ptr = p->get();
_rc = p->rc();
if (_ptr != 0) retain();
return *this;
}
public:
Sptr() : _ptr(0) {}
template <typename U>
Sptr(U *p) : _ptr(p) { _rc = new int(1); }
// Normal and template copy constructors both delegate to private
Sptr(const Sptr &o) : Sptr(&o) {
std::cout << "non-templated copy ctor" << std::endl;
}
template <typename U>
Sptr(const Sptr<U> &o) : Sptr(&o) {
std::cout << "templated copy ctor" << std::endl;
}
// Normal and template assignment operator
Sptr &operator=(const Sptr &o) {
std::cout << "non-templated assignment operator" << std::endl;
return operator=(&o);
}
template <typename U>
Sptr<T> &operator=(const Sptr<U> &o) {
std::cout << "templated assignment operator" << std::endl;
return operator=(&o);
}
// Assignment operator for assigning to void or 0
void operator=(int) {
if (_ptr != 0) release();
_ptr = 0;
_rc = 0;
}
The constructor is initialized with a ref count = 1, but in my assignment operator, I am retaining the object, making the ref count = 2. But it should only be 1 in this case, because bp2 = new B is only one pointer to that object. I've looked over various smart pointer implementation examples, and I can't seem to figure out how they deal with this case that I'm having trouble with.
Thanks for your time!
The assignment operator is riddled with small errors and unnecessary complex anyway. For example, when you assign Sptr<T> to itself it will have funny effects. Most manually written assignment operators should look like this:
T& T::operator= (T const& other) {
T(other).swap(*this);
return *this;
}
... or
T& T::operator= (T other) {
other.swap(*this);
return *this;
}
Once stateful allocators enter the game things change a bit but we can ignore this detail here. The main idea is to leverage the existing work done for the copy constructor and the destructor. Note, that this approach also works if the right hand side isn't T, i.e., you can still leverage a corresponding constructor, the destructor, and swap(). The only potentially additional work is desirable anyway, and trivial to implement: the swap() member. In your case that is very simple, too:
template <typename T>
void Sptr<T>::swap(Sptr<T>& other) {
std::swap(this->_ptr, other._ptr);
std::swap(this->_rc, other._rc);
}
Just a note on your assignment operator taking an int: This is a very bad idea! To reset the pointer, you should probably better have a reset() method. In C++ 2011 you could reasonably have a method taking a std::nullptr_t for this purpose, though.
Define an assignment operator for the raw pointer type. Otherwise, it will construct a new smart pointer with ref count 1, which you will then increase to 2.
Example:
template <typename U>
Sptr<T> &operator=(U *p)
{
if (_ptr != 0)
{
_ptr = p;
_rc = new int(1);
}
return *this;
}
This stuff is notoriously tricky, and there are probably more bugs waiting. I would make the constructor explicit to prevent other unintentional constructions.
From what I see of your code, you need a proper destructor in your smart pointer class to call release and fix the counter. You need at least that modification for your counter to work correctly.
I didn't see a Sptr(T *) constructor in your code, did you omit it?
As a side note, I would probably use a std::pair to store the counter and the T pointer, but your data layout works as it is. As another answer pointed it out, you should pay attention to the self assignment case though.
Here's a minimal implementation following your data layout and interface choices:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class Sptr {
protected:
T *_ptr;
int *_rc;
virtual void retain() {
if (_rc) // pointing to something
++(*_rc);
clog << "retain : " << *_rc << endl;
}
virtual void release() {
if (_rc) {
--(*_rc);
clog << "release : " << *_rc << endl;
if (*_rc == 0) {
delete _ptr;
_ptr = NULL;
delete _rc;
_rc = NULL;
}
}
}
public:
Sptr() : _ptr(NULL), _rc(NULL) {} // no reference
virtual ~Sptr() { release(); } // drop the reference held by this
Sptr(T *p): _ptr(p) { // new independent pointer
_rc = new int(0);
retain();
}
virtual Sptr<T> &operator=(T *p) {
release();
_ptr = p;
_rc = new int(0);
retain();
return *this;
}
Sptr(Sptr<T> &o) : _ptr(o._ptr), _rc(o._rc) {
retain();
}
virtual Sptr<T> &operator=(Sptr<T> &o) {
if (_rc != o._rc){ // different shared pointer
release();
_ptr = o._ptr;
_rc = o._rc;
retain();
}
return *this;
}
};
int main(){
int *i = new int(5);
Sptr<int> sptr1(i);
Sptr<int> sptr2(i);
Sptr<int> sptr3;
sptr1 = sptr1;
sptr2 = sptr1;
sptr3 = sptr1;
}
_rc is the indicator in your class that a pointer is shared with another instance or not.
For instance, in this code:
B *b = new B;
Sptr<B> sptr1(b);
Sptr<B> sptr2(b);
sptr1 and sptr2 are not sharing the pointer, because assignments were done separately, and thus the _rc should be different, which is effectively the case in my small implementation.

smart pointer implementation for derived to base pointers

I have created a smart pointer implementation as given below ::
#include <iostream>
#include <vector>
using namespace std;
class Obj {
int i, j;
public:
Obj() { i = 0 ; j = 0 ; }
Obj(int ii , int jj) : i(ii) , j(jj) { }
void f() { cout << i << endl; }
void g() { cout << j << endl; }
};
class ObjDerived : public Obj
{
int k;
public:
ObjDerived(int kk = 0) :k(kk) { }
void h() { cout << k << endl; }
};
template <typename ULT >
class SP
{
ULT* ptr;
public:
explicit SP(ULT* tptr = NULL) : ptr(tptr) { }
template <typename OTHER>
SP(SP<OTHER>& other)
{
ptr = (ULT*)other.ptr;
}
ULT* operator->() { return ptr; }
ULT& operator*() { return *ptr; }
SP<ULT>& operator=(SP<ULT>& tptr)
{
if(ptr != tptr.ptr)
ptr = tptr.ptr;
return *this;
}
SP<ULT>& operator=(ULT* tptr)
{
ptr = tptr;
return *this;
}
template <typename OTHER>
SP<ULT>& operator=(SP<OTHER>& der) // ??
{
cout << "In operator\n";
this->ptr = (ULT*)der.ptr;
return *this;
}
~SP()
{
if(ptr != NULL )
delete ptr;
}
};
int main()
{
SP<Obj> Sptr2(new Obj(10,20));
SP<ObjDerived> Sptr4(new ObjDerived(80));
Sptr2 = Sptr4; //error in this line
return 0;
}
I am trying to cast a derived class pointer to base class pointer using smart pointer SP . The operator= member function
template <typename OTHER>
SP<ULT>& operator=(SP<OTHER>& der) // ??
{
cout << "In operator\n";
this->ptr = (ULT*)der.ptr;
return *this;
}
is giving the following error ---> error: 'ObjDerived* SP::ptr' is private
I am not able to find out how to achieve the desired pointer conversion using smart pointer. I also searched previous posts on smart pointers but could not find exact answer to my problem.
You can provide public get() function member to be able to retrieve raw pointer. Commonly smart pointers provide this functionality. Small example:
template <typename ULT >
class SP {
// ...
ULT* get() const {return ptr;}
template <typename OTHER>
SP<ULT>& operator=(SP<OTHER>& der) {
cout << "In operator\n";
this->ptr = (ULT*)der.get();
return *this;
}
};
Also you can see Item 45 of Effective C++ for more information about creating smart pointer.
I assumed you are doing this for training tasks, because there are quite good smart pointers implementation, for example, boost::shared_ptr.
Well the member ptr is private - make it public or provide a public access method.
Have you considered using Boost smart pointers instead of attempting to roll your own? They've already gone through all the pain of implementing good smart pointer classes. Even if for some reason you can't use Boost, you can still learn a lot from their classes.
You can make member ptr as private. Or you can use in-built copy mechanism:
Instead of,
this->ptr = (ULT*)der.ptr; // ptr needs to be accessible
Do following:
*this = *((ULT*&)der); // copy using in-built shallow copy