Can I call delete on primitives? - c++

I have a templated class, myFoo, which stores "stuff" of type T which can be either primitive or pointers to complex types. When myFoo is deleted, I want to release all the memory associated with everything it happens to be storing. This means I need to call delete on every pointer being stored but I might also end up calling delete on a primitive. Is this safe??
I've included a sketch of myFoo below to better highlight what's going on. I'm not sure if the behaviour of the destructor is well defined.
template<class T>
class myFoo
{
public:
myFoo(int size)
{
size_ = size;
T* foo = new T[size_];
}
void addFoo(T tmp, int index)
{
foo[index] = tmp;
}
virtual ~myFoo()
{
for(int i=0; i < size_; i++)
{
delete foo[i];
}
delete [] foo;
}
private:
int size_;
T* foo;
}

The only thing you can call delete on is a pointer type. It's an error to call delete on an int, for example. If you arrange your templates so that your code tries to do something that is an error, the compiler will let you know and refuse to compile your code.
So no, you don't have to worry about "accidentally" deleting a non-pointer.

Template specialization
template <class T> struct delete_it;
template <class T> struct delete_it<T*>
{
static void func(T* ptr) { delete ptr; }
};
template <> struct delete_it<int>
{
static void func(int) {}
};
template <> struct delete_it<double>
{
static void func(double) {}
};
Repeat for all primitive types. Then
virtual ~myFoo()
{
for(int i=0; i < size_; i++)
{
delete_it<T>::func(foo[i]);
}
delete [] foo;
}
Unchecked code.

Related

C++ class public function that returns a pointer but doesn't allow deleting that pointer?

template<typename T>
class SmartBuffer {
int capacity;
MyArray<T> *data;
public:
SmartBuffer() {
capacity = 0;
data = nullptr;
}
void alloc(int nbElements) {
if (nbElements > capacity) {
cout << "Allocating smart buffer\n";
if (data!=nullptr) delete data;
data = new MyArray<T>(nbElements + 1);
capacity = nbElements + 1;
}
}
int size() {
return capacity;
}
MyArray<T>* getBuffer() const {
return data;
}
MyArray<T>* getBuffer() {
return data;
}
};
Basically, this class is used for pre-allocation of data, since new[] and delete[](and cudaMalloc and cudaFree) are slow and makes up a significant portion of running time in my problem.
So, I wish to return a pointer to a MyArray object, the caller can modify the object freely. But it must not be allowed to delete the data. Basically, only a SmartBuffer object can delete it's own data.
Is there anyway to do this in C++ other than having another wrapper class and remove the delete operator like below?
void operator delete (void *p) = delete;
A natual solution would be to declare the destructor of MyArray as private and add friend class SmartBuffer<T> to its definition to allow only SmartBuffer to delete it.
However as you stated in a comment you're using MyArray in different contexts and want it to act "normally". Why won't you just implement another type. The least effort is to create an inheriting "wrapper" intended for use with SmartBuffer:
template <typename T> class SmartBuffer; //forward declaration (necessary before 'friend')
template <typename T>
class MySmartArray : public MyArray<T>
{
private: ~MySmartArray() {}
private: MySmartArray() {} //disallow also the constructor from external usage
friend class SmartBuffer<T>;
};
Then you go:
template<typename T>
class SmartBuffer {
int capacity;
MySmartArray<T> *data;
public:
~SmartBuffer { delete data; } //SmartBuffer can delete MySmartArray
//and replace everywhere MyArray to MySmartArray ...
//...
};
Now an external user won't be able to delete it:
int main()
{
SmartBuffer<int> buff;
auto ptr = buff.getBuffer();
delete ptr; // error: 'MySmartArray<T>::~MySmartArray() [with T = int]' is private within this context
return 0;
}

Error when initializing an object from template class. see reference to class template instantiation

I know finding errors in code is not something which is done in StackOverflow but I'm posting here because I'm truly desperate as I've been looking for a solution for a while now completely fruitless.
I have a task of implementing my own Stack class (as a linked list). No problem with that part. Here's my code
template<typename T>
struct node {
T inf;
node* link;
};
template <typename T>
class myStack {
private:
node<T> *start; //Decalration of class myStack. I've left only the default constructor.
public:
myStack();
}
template<typename T>
myStack<T>::myStack() {
start = NULL;
}
Everything works as intended. Next part of the task is implementing a queue using two stacks. Basically enqueuing means pushing an element into the first stack, and dequeuing transferring all elements from the first stack to the second and then popping the top one.
Implementation of the queue:
template<class T>
class QueueStacks {
myStack<T> stack1;
myStack<T> stack2;
public:
QueueStacks();
void enqueue(T&);
T& dequeue();
void print();
};
template<typename T>
QueueStacks<T>::QueueStacks() { //No need I believe, for default constructor, but I left it for clarity purposes
}
template<typename T>
void QueueStacks<T>::enqueue(T& obj) {
if (stack1.empty()) {
transferTwoToOne(); //Function transferTwoToOne works as intended, so I didn't deem it necessary to include include its implementation
}
else {
stack1.push(); //void myStack::push() works as intended, so I deliberately left out its implmentation
}
}
template<typename T>
T& QueueStacks<T>::dequeue() {
T x;
if (stack1.empty() && stack2.empty()) {
cout << "Attempt to pop from an empty stack";
}
else {
if (stack2.empty()) {
transferOneToTwo(); //Same for function transferOneToTwo
stack2.pop(x);
}
else
stack2.pop(x); //same for pop
return x;
}
}
template<typename T>
void QueueStacks<T>::print() {
T x;
if (stack2.empty()) {
transferOneToTwo();
}
while (!stack2.empty()) {
stack2.pop(x);
cout << x << " ";
}
}
The error comes when I try to initialize an object from class queue. E.g
int main()
{
QueueStacks<int> obj1;
for (int i = 0; i < 5; i++){
obj1.push(i);
}
obj1.print();
return 0;
}
The compiler shows this:note: see reference to class template instantiation 'QueueStacks' being compiled. I got 3 errors:
What am I doing wrong when trying to initialize obj1?
In order to call push on obj1, the QueueStacks<int> would have to have a push member function.
Did you mean to invoke enqueue?

error: 'template<class T> class Dynamic_Array' used without template parameters

I've been getting this error for some time, and I have no clue how to fix it.
I searched for similar problem here on stack overflow, but I've failed to find anything.
Source code:
template <typename T>
class Dynamic_Array
{
private:
T* actual_array;
unsigned int number_of_elements;
public:
Dynamic_Array() {}
~Dynamic_Array() {delete[] actual_array;}
unsigned int get_size() const {return number_of_elements;}
T& operator [](unsigned int index) {return actual_array[index];}
void operator +=(T&);
void operator -=(unsigned int);
};
template <typename T> /*Not sure if this is needed, but compiler doesn't mind, still prints the same error*/
void Dynamic_Array<T>::operator+=(T& object)
{
if(number_of_elements>1)
{
T* temp_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
temp_array[i]=actual_array[i];
}
delete[] actual_array;
actual_array = new T[number_of_elements+1];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array=NULL;
actual_array[number_of_elements]=object;
number_of_elements++;
}
else
{
number_of_elements++;
actual_array = new T[1];
}
}
void Dynamic_Array<T>::operator-=(unsigned int index)
{
T* temp_array = new T[number_of_elements-1];
for(unsigned int i=0, j=0;i<number_of_elements;i++)
{
if(i!=index)
{
temp_array[j]=actual_array[i];
j++;
}
}
delete[] actual_array;
number_of_elements--;
actual_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array = NULL;
}
According to compiler, the error is present in line 18 (the empty one between "};" and "template"
As I said, I have no idea what I screwed up, so any help is appreciated.
When you define member functions outside of a class template declaration then you need to specify the template for each function. When you define
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
You need to have the template part as well like
template <typename T>
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
This has to be present for every function definition that you do out of line. A single template <typename T> at the start of all the definition does not apply to all of the function definitions.
Dynamic_Array is a template class so when defining operator+= and operator-= outside the scope of the class you need to provide template type as follows:
template<typename T> void Dynamic_Array<T>::operator+=(T& object) {
//...
}
template<typename T> void Dynamic_Array<T>::operator-=(unsigned int index) {
//...
}
Also, I should note that it is somewhat odd to have void as a return type for operator+= and operator-=, typically you should return a reference to the altered instance of this, i.e:
template<typename T> Dynamic_Array<T>& Dynamic_Array<T>::operator+=(const T& object) {
//...
}

Cast a polymorphic smart pointer object

I implemented the following smart pointer template class:
#ifndef __ProjectManager__mSharedPtr__
#define __ProjectManager__mSharedPtr__
#include <stdio.h>
#include "RefCount.h"
template <class T>
class mSmartPtr {
T *data;
RefCount *rc;
public:
mSmartPtr(T* srcPtr);
mSmartPtr(const mSmartPtr&);
~mSmartPtr();
T* operator->() const;
T& operator*() const;
mSmartPtr<T>& operator=( mSmartPtr&);
mSmartPtr<T> operator()(mSmartPtr&);
};
template<class T>
mSmartPtr<T> mSmartPtr<T>::operator()(mSmartPtr<T>& src) {
return dynamic_cast<??>(src);
}
template <class T>
mSmartPtr<T>::mSmartPtr(T *srcPtr):
data(srcPtr) {
rc = new RefCount();
rc->add();
}
template<class T>
mSmartPtr<T>::~mSmartPtr() {
if (rc->remove() == 0) {
delete data;
delete rc;
}
}
template<class T>
mSmartPtr<T>::mSmartPtr(const mSmartPtr<T> &src):
data(src.data), rc(src.rc) {
rc->add();
}
template <class T>
T* mSmartPtr<T>::operator->() const {
return data;
}
template<class T>
T& mSmartPtr<T>::operator*() const {
return &data;
}
template <class T>
mSmartPtr<T>& mSmartPtr<T>::operator=( mSmartPtr<T> &src) {
if (this != &src) {
if (rc->remove() == 0) {
delete data;
delete rc;
}
data = src.data;
rc = src.rc;
rc->add();
}
return *this;
}
#endif /* defined(__ProjectManager__mSharedPtr__) */
let's say my application contains the following classes:
class Base
{
protected:
...
public:
virtual ~Base() =0;
...
};
class Derived1 : public Base
{
protected:
...
public:
virtual ~Derived1() {}
...
};
class Derived2 : public Base
{
protected:
...
public:
virtual ~Derived2() {}
...
};
and I need store data at the following way:
int int main(int argc, char const *argv[])
{
std::vector<mSmartPtr<Base>> v;
mSmartPtr<Derived1> d1 = foo();
v.push_back(d1);
return 0;
}
I need to fix somehow the cast operator, but how? how do I get the base class in the dynamic cast?
#Guvante
Your code did not work , I modified it as follows but I don't know if will work well
template<class T>
mSmartPtr<T> mSmartPtr<T>::operator ()(mSmartPtr<T>& src) {
mSmartPtr<T> retVal(dynamic_cast<T*>(src.data));
retVal.rc = src.rc;
retVal.rc.Add();
return retVal;
}
I think there is a better alternative to this. Unless you have a different location where you need to be able to do this, you can avoid the headache by changing the way you create the object.
int main(int argc, char const *argv[])
{
std::vector<mSmartPtr<Base>> v;
mSmartPtr<Base> d1 = static_cast<Base*>(foo());
v.push_back(d1);
return 0;
}
Just avoid creating an mSmartPtr that is typed differently than your vector.
In your conversion method extract the underlying pointer and cast it then put it into the new smart pointer. Don't forget to copy the RefCount and ensure that your target class has a virtual destructor (so the correct one gets called no matter which smart pointer gets dispossed last).
I couldn't figure out how to define it externally but an inline definition worked.
//In the definition, replacing this line
//mSmartPtr<T> operator()(mSmartPtr&)
template<class Tdest>
operator mSmartPtr<Tdest>() {
mSmartPtr<Tdest> retVal(static_cast<Tdest*>(data));
retVal.rc = rc;
retVal.rc.Add();
return retVal;
}
In theory you could also add a version that takes a r-value if you are using C++11 but I think that would take a little work to do correctly so I avoided it.

deallocation of pointers

I have a list pointer in type of A (called ListA) container a vector of pointers B. (Each A object is a container class that has a private attribute: std<vector> *B). Then, I declare a pointer (called C having the same type as A), make a for-loop through ListA to get all pointers B and put them in C. When I quit my program, I deallocate ListA first, ListA in turn deallocates their own vector of pointers B. Then I deallocate pointer C, but the program crashes.
I have debugged this a bit and know that pointer C at the time of deallocation points to nothing, so it doesn't know what to deallocate.
Am I doing wrong? Or what is the solution for my problems?
Sorry, I'll put my code below
//Class A
#pragma once
#include "MyContainer.h"
class B;
class A
{
public:
A();
~A();
MyContainer<B> *pListOfB;
}
A::A()
{
pListOfB = new MyContainer<B>;
}
A::~A()
{
if(pListOfB)
{
delete pListOfB;
pListOfB = NULL;
}
}
//Class C
#pragma once
#include "MyContainer.h"
class B;
class C
{
public:
C();
~C();
MyContainer<B> *pListOfB;
void getListOfB(MyContainer<A> *pListOfA);
}
C::C()
{
pListOfB = new MyContainer<B>;
}
C::~C()
{
if(pListOfB)
{
delete pListOfB;
pListOfB = NULL;
}
}
void C::getListOfB(MyContainer<A> *pListOfA)
{
for(pListOfA->isBegin(); !pListOfA->isEnd();)
{
A *pA = pListOfA->getNext();
for(pA->isBegin(); !pA->isEnd();)
{
B* pB = pA->*pListOfB->getNext();
pListOfB->add(pB);
}
}
}
//Class MyContainer
#pragma once
#include <vector>
template <class T>
class MyContainer
{
public:
MyContainer(void);
~MyContainer(void);
T* getNext();
void removeAll();
void add(T* t);
void isBegin();
bool isEnd();
private:
std::vector<T*> items;
typename std::vector<T*>::iterator it;
};
template <class T> MyContainer<T>::~MyContainer()
{
removeAll();
}
template <class T> void MyContainer<T>::add(T *t)
{
items.push_back(t);
}
template <class T> void MyContainer<T>::removeAll()
{
while(!isEmpty())
{
std::vector<T*>::iterator tempIt =items.begin();
T* t = (*tempIt);
items.erase(tempIt);
delete t;
t=NULL;
}
}
template <class T>
T* MyContainer<T>::getNext()
{
if(isEnd() || isEmpty())
return NULL;
return (T*)(*(it++));
}
template <class T>
void MyContainer<T>::isBegin()
{
it = items.begin();
}
template <class T>
bool MyContainer<T>::isEnd()
{
return it==items.end();
}
I do the following action:
1. Initial a list A object : MyContainer *pListOfA;
2. Insert B data to each A object in pListOfA
3. Initial C object
4. Call C object operation getListOfB to get B data from pListOfA.
5. Quit program
Program first dealloc pListOfA, each A then dealloc their own pListOfB. After that program dealloc C object in turn dealloc pListOfB attribute of C. But pListOfB point to nothing because pListOfA deallocs every data. So my program crash.
I fix by rem the line delete pListOfB in the dtor of class C but I got a warning memory leak at that line.
That's all my problem. Please show me the right way. Thanks in advance.
first, you allocate
then you "take and put" somewhere (not allocating, just copying pointers)
then you deallocate
then you deallocate. ...wait
The right way is not to use plain pointers.
The moment you start to write delete pointer;, you have to reconsider if you really need that pointer and if you do need it, if there is not some pre-packaged smart-pointer class that can take the burden of memory management from you.
The example code you posted can be written entirely without the use of pointers:
//Class A
#pragma once
#include "MyContainer.h"
#include "B.h"
class A
{
public:
A() { };
~A() { };
MyContainer<B> ListOfB;
};
//Class C
#pragma once
#include "MyContainer.h"
#include "B.h"
class C
{
public:
C() { };
~C() { };
MyContainer<B> ListOfB;
void getListOfB(MyContainer<A>& ListOfA);
};
void C::getListOfB(MyContainer<A>& ListOfA)
{
for(ListOfA.isBegin(); !ListOfA.isEnd();)
{
A& anA = ListOfA.getNext();
for(anA.ListOfB.isBegin(); !anA.ListOfB.isEnd();)
{
B aB = anA.ListOfB.getNext();
ListOfB.add(aB);
}
}
}
//Class MyContainer
#pragma once
#include <vector>
template <class T>
class MyContainer
{
public:
MyContainer(void);
~MyContainer(void) { };
T& getNext();
void removeAll();
void add(const T& t);
void isBegin();
bool isEnd();
private:
std::vector<T> items;
typename std::vector<T>::iterator it;
};
template <class T> void MyContainer<T>::add(const T& t)
{
items.push_back(t);
}
template <class T> void MyContainer<T>::removeAll()
{
items.clear();
}
template <class T>
T& MyContainer<T>::getNext()
{
if(isEnd() || isEmpty())
return throw std::out_of_range("");
return *it++;
}
template <class T>
void MyContainer<T>::isBegin()
{
it = items.begin();
}
template <class T>
bool MyContainer<T>::isEnd()
{
return it==items.end();
}
If the B instances need to be shared between class A and class C (the lists in A and C refer both to the same B objects), then you could store shared pointers in the lists.