Question
The homework is creating own my smart_ptr() class. I want to pass from case7 to case 13. count of number of refernce cause failing from
The homework is creating own my smart_ptr() class. I want to pass from case7 to case 13. count of number of refernce cause failing from case 7 to cas 13
1. Don't use shared ptr, unique ptr and weak ptr. 2. Don't fix anything below ourtype struct.
Below the ourtype is source code to evaluate my source code, so you can only fix the source code above ourtype.
#include
#include
#include
#include
using namespace std;
class null_ptr_exception : public runtime_error
{
public:
null_ptr_exception(const char* msg): runtime_error(msg)
{
}
private:
char* msg;
};
template
class smart_ptr
{
private:
T* ptr_; // pointer to the referred object
int* ref_; // pointer to a reference count
virtual smart_ptr * some_impl() const
{
return new smart_ptr(*this) ;
}
public:
smart_ptr() noexcept :ptr_(nullptr), ref_(nullptr)
{
}
// Create a smart_ptr that is initialized to NULL. The reference count
// should be zero.
explicit smart_ptr(T* raw_ptr)
{
T* temp ;
temp = new T(*raw_ptr);
ref_ = new int(1);
delete raw_ptr;
raw_ptr= temp;
}
// Create a smart_ptr that is initialized to raw_ptr. The reference count
// should be one.
smart_ptr(const smart_ptr& rhs) noexcept
{
ptr_=rhs.ptr_;
ref_=rhs.ref_;
(*ref_)++;
}
// Copy construct a pointer from rhs. The reference count should be
// incremented by one.
smart_ptr(smart_ptr&& rhs) noexcept
{
ptr_ = nullptr;
ref_ = 0;
// Copy the datas from the source object.
ptr_ = rhs.ptr_;
ref_ = rhs.ref_;
// Release the pointer from the source object so that the destructor does not free the memory multiple times.
rhs.ptr_ = nullptr;
rhs.ref_ = 0;
}
// Move construct a pointer from rhs.
smart_ptr& operator=(const smart_ptr& rhs) noexcept
{
if (this != &rhs) // Avoid self assignment
{
// if reference become zero, delete the ptr & ref
if(ref_ == nullptr || ref_==0)
{
delete (ptr_);
delete (ref_);
}
// Copy the data and reference pointer
ptr_ = rhs.ptr_;
ref_ = rhs.ref_;
if(ref_ == NULL )
{
delete ptr_;
delete ref_;
}
else
++(*ref_);
}
return *this;
}
// This assignment should make a shallow copy of the right-hand side's
// pointer data. The reference count should be incremented as appropriate.
smart_ptr& operator=(smart_ptr&& rhs)noexcept
{
int* temp_ref = nullptr;
T* temp_ptr = nullptr;
if (rhs.ref_)
{
temp_ref = new int(*rhs.ref_);
temp_ptr = new T (*rhs.ptr_);
}
delete ref_;
delete ptr_;
ptr_ = temp_ptr;
ref_ = temp_ref;
return *this;
}
// This move assignment should steal the right-hand side's pointer data.
bool clone()
{
bool result =false;
T* temp;
if(ref_ != nullptr || ptr_ != nullptr)
{
--(*ref_);
ptr_ = new T(*ptr_);
ref_ =new int(1);
return true;
}
else
return result;
}
// If the smart_ptr is either NULL or has a reference count of one, this
// function will do nothing and return false. Otherwise, the referred to
// object's reference count will be decreased and a new deep copy of the
// object will be created. This new copy will be the object that this
// smart_ptr points and its reference count will be one.
int ref_count() const noexcept
{
if(ref_ != nullptr)
return *ref_;
else
return 0;
}
// Returns the reference count of the pointed to data.
T& operator*()
{
if(ptr_!=nullptr)
{
return (*ptr_);
}
else
throw null_ptr_exception("Invalid this ptr");
}
// The dereference operator shall return a reference to the referred object.
// Throws null_ptr_exception on invalid access.
T* operator->()
{
if(ptr_!=nullptr)
{
return (ptr_);
}
else
throw null_ptr_exception("Invalid this ptr");
}
// The arrow operator shall return the pointer ptr_. Throws null_ptr_exception
// on invalid access.
~smart_ptr()
{
if(ref_ == nullptr)
{
delete ptr_;
delete ref_;
}
else if((*ref_) > 1)
{
--(*ref_);
}
else if((*ref_) <=1)
{
delete ref_;
}
} // deallocate all dynamic memory
};
/*
void g()
{
throw std::exception();
}
void f()
{
int* pI = new int(2);
*pI = 3;
g();
// Oops, if an exception is thrown, pI is never deleted
// and we have a memory leak
delete pI;
}
int main()
{
try
{
f();
}
catch(...)
{ }
return 0;
}
*/
#include
#include
#include
#include
struct OurType
{
explicit OurType(int v = 0) : m_value(v) { m_count++; }
OurType(const OurType& other) : m_value(other.m_value)
{ m_count++; m_asstcopycount++; }
~OurType() { m_count--; }
OurType& operator=(const OurType& rhs)
{ m_value = rhs.m_value; m_asstcopycount++; return *this; }
int m_value;
static int m_count;
static int m_asstcopycount;
};
inline
bool operator==(const OurType& lhs, const OurType& rhs)
{ return lhs.m_value == rhs.m_value; }
inline
bool operator<(const OurType& lhs, const OurType& rhs)
{ return lhs.m_value < rhs.m_value; }
inline
bool operator!=(const OurType& lhs, const OurType& rhs)
{ return ! (lhs == rhs); }
inline
bool operator<=(const OurType& lhs, const OurType& rhs)
{ return ! (rhs < lhs); }
inline
bool operator>=(const OurType& lhs, const OurType& rhs)
{ return ! (lhs < rhs); }
inline
bool operator>(const OurType& lhs, const OurType& rhs)
{ return rhs < lhs; }
inline
bool operator==(const OurType& lhs, int rhs)
{ return lhs.m_value == rhs; }
inline
bool operator!=(const OurType& lhs, int rhs)
{ return ! (lhs == rhs); }
#include
inline
std::ostream& operator<<(std::ostream& lhs, const OurType& rhs)
{ return lhs << rhs.m_value; }
int OurType::m_count = 0;
int OurType::m_asstcopycount = 0;
inline int itemcount()
{
return OurType::m_count;
}
inline int nasstcopys()
{
return OurType::m_asstcopycount;
}
std::set addrs;
bool recordaddrs = false;
int throwBadAlloc = 0;
// value of 0 means allocations don't throw
// value of 1 means 1st allocation throws
// value of 2 means 2nd allocation throws
// value of n means nth allocation throws
void* operator new(size_t n)
{
if (recordaddrs) {
if (throwBadAlloc == 1)
throw std::bad_alloc();
else if(throwBadAlloc > 1)
throwBadAlloc--;
}
void* p = malloc(n);
if (recordaddrs)
{
recordaddrs = false;
addrs.insert(p);
recordaddrs = true;
}
return p;
}
void operator delete(void* p) noexcept
{
if (recordaddrs)
{
recordaddrs = false;
std::set::iterator it = addrs.find(p);
if (it != addrs.end())
addrs.erase(it);
recordaddrs = true;
}
free(p);
}
void testone(int n)
{
smart_ptr dsp0;
smart_ptr dsp1 {new double {3.14}};
smart_ptr dsp2, dsp3;
switch (n)
{
default: {
assert(false);
} break; case 1: {
assert(dsp0.ref_count() == 0);
} break; case 2: {
assert(dsp1.ref_count() == 1);
} break; case 3: {
dsp0 = dsp1;
assert(dsp0.ref_count() == 2);
} break; case 4: {
dsp3 = dsp2 = dsp1;
assert(dsp3.ref_count() == dsp2.ref_count() &&
dsp1.ref_count() == dsp2.ref_count() &&
dsp1.ref_count() == 3);
} break; case 5: {
dsp1 = dsp0;
assert(dsp1.ref_count() == 0 && dsp2.ref_count() == 0);
} break; case 6: {
assert(std::is_nothrow_constructible>::value);
assert(std::is_nothrow_copy_constructible>::value);
// possible XCode compiler bug for following two asserts
//assert(std::is_nothrow_constructible,int*>::value);
//assert(std::is_nothrow_assignable::value);
assert(std::is_nothrow_move_assignable>::value);
assert(std::is_nothrow_move_constructible>::value);
assert(!noexcept(std::declval>().clone()));
assert(!noexcept(std::declval>().operator*()));
assert(!noexcept(std::declval>().operator->()));
assert(noexcept(std::declval>().ref_count()));
} break; case 7: {
{
// testing constructor
smart_ptr osp0 {new OurType{0}};
assert(itemcount() == 1);
}
cout << itemcount();
assert(itemcount() == 0);
} break; case 8: {
{
// testing assignment operator
smart_ptr osp0 {new OurType{0}};
assert(itemcount() == 1);
smart_ptr osp1;
osp1 = osp0;
assert(itemcount() == 1);
}
assert(itemcount() == 0);
} break; case 9: {
{
// testing copy constructor
smart_ptr osp0 {new OurType{0}};
assert(itemcount() == 1);
smart_ptr osp1{osp0};
assert(osp0.ref_count() == 2);
assert(osp1.ref_count() == 2);
assert(itemcount() == 1);
}
assert(itemcount() == 0);
} break; case 10: {
{
// testing move constructor
smart_ptr osp0 {new OurType{0}};
assert(itemcount() == 1);
smart_ptr osp1{std::move(osp0)};
assert(itemcount() == 1);
}
assert(itemcount() == 0);
} break; case 11: {
{
// testing move assignment
smart_ptr osp0 {new OurType{0}};
assert(osp0.ref_count() == 1);
assert(itemcount() == 1);
smart_ptr osp1;
osp1 = std::move(osp0);
assert(osp1.ref_count() == 1);
assert(osp0.ref_count() == 0);
assert(itemcount() == 1);
}
assert(itemcount() == 0);
} break; case 12: {
{
// testing move constructor
smart_ptr osp0 {new OurType{0}};
assert(osp0.ref_count() == 1);
assert(itemcount() == 1);
smart_ptr osp1{std::move(osp0)};
assert(osp1.ref_count() == 1);
assert(osp0.ref_count() == 0);
assert(itemcount() == 1);
}
assert(itemcount() == 0);
} break; case 13: {
{
// testing move assignment
smart_ptr osp0 {new OurType{0}};
assert(osp0.ref_count() == 1);
assert(itemcount() == 1);
smart_ptr osp1;
osp1 = std::move(osp0);
assert(osp1.ref_count() == 1);
assert(osp0.ref_count() == 0);
assert(itemcount() == 1);
}
assert(itemcount() == 0);
} break; case 14: {
{
// testing assignment operator
smart_ptr osp0;
assert(itemcount() == 0);
smart_ptr osp1;
osp1 = osp0;
assert(itemcount() == 0);
}
assert(itemcount() == 0);
} break; case 15: {
try {
*dsp0;
assert(0);
}
catch (...) { }
} break; case 16: {
smart_ptr osp{new OurType{42}};
try {
assert((*osp).m_value==42);
}
catch (...) {
assert(0);
}
} break; case 17: {
smart_ptr osp;
try {
(*osp).m_value; // should throw
assert(0);
}
catch (...) { }
} break; case 18: {
smart_ptr osp{new OurType{42}};
try {
assert(osp->m_value == 42);
}
catch (...) {
assert(0);
}
} break; case 19: {
smart_ptr osp;
try {
osp->m_value; // should throw
assert(0);
}
catch (...) { }
} break; case 20: {
assert(!dsp0.clone());
assert(!dsp1.clone());
} break; case 21: {
dsp3 = dsp2 = dsp1;
assert(dsp1.clone());
assert(dsp1.ref_count() == 1 && dsp2.ref_count() == 2 && dsp3.ref_count() == 2);
assert(*dsp1 == 3.14 && *dsp2 == 3.14 && *dsp3 == 3.14);
} break; case 22: {
dsp3 = dsp2 = dsp1;
recordaddrs = true;
throwBadAlloc = 1; // first allocation throws exception
size_t oldSize = addrs.size();
try {
dsp1.clone();
assert(0);
}
catch(std::bad_alloc) { }
// test for strong guarantee, no change to dsp1
assert(*dsp1 == *dsp2 && dsp1.ref_count() == dsp2.ref_count());
assert(addrs.size() == oldSize);
recordaddrs = false;
} break; case 23: {
dsp3 = dsp2 = dsp1;
recordaddrs = true;
throwBadAlloc = 2; // second alocation throws exception
size_t oldSize = addrs.size();
try {
dsp1.clone();
assert(0);
}
catch(std::bad_alloc) { }
// test for strong guarantee, no change to dsp1
assert(*dsp1 == *dsp2 && dsp1.ref_count() == dsp2.ref_count());
assert(addrs.size() == oldSize);
recordaddrs = false;
} break; case 24: {
dsp3 = dsp2 = dsp1;
assert(*dsp1 == *dsp2 && *dsp2 == *dsp3 && *dsp1 == 3.14);
assert(dsp1.ref_count() == dsp2.ref_count() &&
dsp2.ref_count() == dsp3.ref_count() &&
dsp1.ref_count() == 3);
} break; case 25: {
dsp3 = dsp2 = dsp1;
dsp3 = dsp0;
assert(*dsp1 == *dsp2 && *dsp1 == 3.14);
assert(dsp1.ref_count() == dsp2.ref_count() &&
dsp1.ref_count() == 2 &&
dsp3.ref_count() == 0);
}
}
}
int main()
{
cout << "Enter a test number (1 to 25): ";
int n;
cin >> n;
if (n < 1 || n > 25)
{
cout << "Bad test number" << endl;
return 1;
}
testone(n);
cout << "Passed test " << n << endl;
}
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started