Restrict client from allocating objects on heap C++ - c++

I have a class X and method addX() which allocates objects of X on the heap. I want to restrict client-code from directly allocating objects of X (so that the X *ptr = new X is not allowed).
I've declared new, new[] operators private, but since I'm allocating X's objects through addX() I need to define them (operators). So, what's their definition should look like?

Hide the constructors, use a factory function:
class A
{
public:
static A* create() { return new A; }
static void destroy(A* a) { delete a; }
protected:
A() {}
A(const A&) {}
A& operator=(const A&) {}
};

This is pretty easy.
#include <iostream>
#include <new>
class X {
public:
static void addX()
{
X* p1 = new X;
delete p1;
}
private:
void* operator new(std::size_t sz)
{
std::cout << "custom new for size " << sz << '\n';
return ::operator new(sz);
}
void* operator new[](std::size_t sz)
{
return ::operator new(sz);
}
};
int main()
{
X::addX();
}

Related

How can I access member function of a class via a shared ptr to a shared ptr?

I have two classes, foo and bar, where bar contains a pointer to foo, as below.
#include<iostream>
#include<memory>
class foo {
private:
int num{4};
public:
void sum(const int& to_add) {num += to_add;}
int access_num() {return num;}
};
class bar {
private:
std::shared_ptr<foo> ptr;
public:
void change_ptr(foo& f) {
auto new_ptr = std::make_shared<foo>(f);
ptr = std::move(new_ptr);
}
std::shared_ptr<foo> access_ptr() { return ptr; }
};
If I want to execute the member function sum() of foo via the pointer in bar, how do I do it?
Currently, trying
foo f;
std::shared_ptr<bar> bar_ptr = std::make_shared<bar>();
bar_ptr->change_ptr(f);
// Add three to the int stored in f via the pointer
bar_ptr->access_ptr()->sum(3);
std::cout << f.access_num() << std::endl;
does not work, outputting 4.
This code
void change_ptr(foo& f) {
auto new_ptr = std::make_shared<foo>(f); // copy constructor
ptr = std::move(new_ptr);
}
calls a copy constructor to create an instance of foo on the heap and manage it with std::shared_ptr. You can check it if you delete the copy constructor in foo declaration. The code won't compile. Note that you'll have to provide at least a default constructor since the rule of zero doesn't work if you have explicitly deleted copy constructor.
class foo {
private:
int num{4};
public:
foo() = default;
foo(foo const &other) = delete;
void sum(const int& to_add) {num += to_add;}
int access_num() {return num;}
};
foo f is an automatic variable stored on the stack. There is no much use to manage it with std::shared_ptr. What you probably need is to create an instance of foo on the heap and use std::shared_ptr's to work with it:
#include<memory>
class foo {
private:
int num{4};
public:
void sum(const int& to_add) {num += to_add;}
int access_num() {return num;}
};
class bar {
private:
std::shared_ptr<foo> ptr;
public:
void change_ptr(std::shared_ptr<foo> f) {
ptr = std::move(f); // f is already a copy, so we can safely move it
}
std::shared_ptr<foo> access_ptr() { return ptr; }
};
int main() {
auto f = std::make_shared<foo>();
std::shared_ptr<bar> bar_ptr = std::make_shared<bar>();
bar_ptr->change_ptr(f);
bar_ptr->access_ptr()->sum(3);
std::cout << f->access_num() << std::endl;
}

How to deal with double (or multiple) copy constructors for class with pointers

There is a class called "X" like this:
class X {
private:
int *ptr;
public:
X() {
ptr = new int[2];
ptr[0] = 0;
ptr[1] = 0;
}
X(int a, int b) {
ptr = new int[2];
ptr[0] = a;
ptr[1] = b;
}
X(const X &val) {
delete[] ptr;
ptr = new int[2];
ptr[0] = val.ptr[0];
ptr[1] = val.ptr[1];
}
X get() {
X ret(ptr[0], ptr[1]);
return ret;
}
};
Suppose that there are variable X that is defined with X v(2, 3).
If we call v.get(), it's okay.
But, if we call v.get().get(), it's not okay. It produces runtime error in delete[] ptr section in copy constructor, which the content is that I am trying to delete the undefined (0xcccccccc) pointer.
One possible option for dealing with this is, that using C++-STL like <array> or <vector>. But I want to implement with pointer.
How to deal with this runtime error, with pointer-based implementation?
The simple answer is that you shouldn't delete[] ptr in the copy constructor, because it is uninitialised. You don't need to delete[] ptr in assignment, either. The only place delete or delete[] should occur is in a destructor.
Tidying up your class, without changing from owning raw pointers
class X {
private:
int *ptr;
public:
X() : X(0, 0) { }
X(int a, int b) : ptr(new int[2]) {
ptr[0] = a;
ptr[1] = b;
}
X(const X &val) : X(val.ptr[0], val.ptr[1]) { }
X& operator=(const X &val)
{
ptr[0] = val.ptr[0];
ptr[1] = val.ptr[1];
return *this;
}
X(X&& val) : ptr(val.ptr) {
val.ptr = nullptr;
}
X& operator=(X&& val) {
std::swap(ptr, val.ptr);
return *this;
}
~X() { delete[] ptr; }
X get() {
return *this;
}
};
As a point of nomenclature, a constructor is only a "copy constructor" if it takes an instance of the class as it's single (non-default) parameter. X::X(int, int) is just a constructor. That means there are at most 4 copy constructors (otherwise they would be ambiguous under overload resolution)
X::X(X &)
X::X(const X &)
X::X(volatile X &)
X::X(const volatile X &)
However defining more than one is a terrible idea, unless you in an obfuscation contest

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.

C++11 - Way to detect the operator new[]

I'm trying to make something like this work:
struct holder {
std::function<void()> destroyer;
template<typename T>
holder(T) = delete;
template<typename T>
holder(std::enable_if< WAS CREATED WITH new > pointer) {
destroyer = [=] { delete pointer; };
};
template<typename T>
holder(std::enable_if< WAS CREATED WITH new[] > array) {
destroyer = [=] { delete[] array; };
};
virtual ~holder() {
destroyer();
};
};
In a way that I could then simply make return new test; and return = new test[10]; on a function that would return holder. But I found out that it won't ever be treated as an array, as operator new[] returns a pointer.
Is there any way to achieve the desired result?
Thanks! :)
It is impossible; whether or not new or new[] was used is not part of the pointer's type information.
The only way I know of is through placement-new:
#include <new>
#include <iostream>
struct A
{
void* operator new(std::size_t n, void* ptr)
{
std::cout << "operator new()\n";
return ptr;
}
void* operator new[](std::size_t n, void* ptr)
{
std::cout << "operator new[]\n";
return ptr;
}
};
int main()
{
A* ptr;
new (ptr) A();
new (ptr) A[5];
}

Is it possible to prevent stack allocation of an object and only allow it to be instantiated with 'new'?

Is it possible to prevent stack allocation of an object and only allow it to be instiated with 'new' on the heap?
One way you could do this would be to make the constructors private and only allow construction through a static method that returns a pointer. For example:
class Foo
{
public:
~Foo();
static Foo* createFoo()
{
return new Foo();
}
private:
Foo();
Foo(const Foo&);
Foo& operator=(const Foo&);
};
In the case of C++11
class Foo
{
public:
~Foo();
static Foo* createFoo()
{
return new Foo();
}
Foo(const Foo &) = delete; // if needed, put as private
Foo & operator=(const Foo &) = delete; // if needed, put as private
Foo(Foo &&) = delete; // if needed, put as private
Foo & operator=(Foo &&) = delete; // if needed, put as private
private:
Foo();
};
You could make the constructor private, then provide a public static factory method to create the objects.
The following allows public constructors and will stop stack allocations by throwing at runtime. Note thread_local is a C++11 keyword.
class NoStackBase {
static thread_local bool _heap;
protected:
NoStackBase() {
bool _stack = _heap;
_heap = false;
if (_stack)
throw std::logic_error("heap allocations only");
}
public:
void* operator new(size_t size) throw (std::bad_alloc) {
_heap = true;
return ::operator new(size);
}
void* operator new(size_t size, const std::nothrow_t& nothrow_value) throw () {
_heap = true;
return ::operator new(size, nothrow_value);
}
void* operator new(size_t size, void* ptr) throw () {
_heap = true;
return ::operator new(size, ptr);
}
void* operator new[](size_t size) throw (std::bad_alloc) {
_heap = true;
return ::operator new[](size);
}
void* operator new[](size_t size, const std::nothrow_t& nothrow_value) throw () {
_heap = true;
return ::operator new[](size, nothrow_value);
}
void* operator new[](size_t size, void* ptr) throw () {
_heap = true;
return ::operator new[](size, ptr);
}
};
bool thread_local NoStackBase::_heap = false;
This should be possible in C++20 using a destroying operator delete, see p0722r3.
#include <new>
class C
{
private:
~C() = default;
public:
void operator delete(C *c, std::destroying_delete_t)
{
c->~C();
::operator delete(c);
}
};
Note that the private destructor prevents it from being used for anything else than dynamic storage duration. But the destroying operator delete allows it to be destroyed via a delete expression (as the delete expression does not implicitly call the destructor in this case).
You could create a header file that provides an abstract interface for the object, and factory functions that return pointers to objects created on the heap.
// Header file
class IAbstract
{
virtual void AbstractMethod() = 0;
public:
virtual ~IAbstract();
};
IAbstract* CreateSubClassA();
IAbstract* CreateSubClassB();
// Source file
class SubClassA : public IAbstract
{
void AbstractMethod() {}
};
class SubClassB : public IAbstract
{
void AbstractMethod() {}
};
IAbstract* CreateSubClassA()
{
return new SubClassA;
}
IAbstract* CreateSubClassB()
{
return new SubClassB;
}