Generic list deleting non pointers - c++

I have a generic list with a template
template<class t>
class GenericList {
//the data is storeed in a chained list, this is not really important.
struct c_list { t data; c_list* next; ...constructor... };
public:
bool isDelete;
GenericList() : isDelete(false) {...}
void add(t d) {
c_list* tmp = new c_list(d, first->next);
//this is not really important again...
}
~GenericList() {
c_list* tmp = first;
c_list* tmp2;
while(tmp->next!=NULL) {
if (isDelete) { delete tmp->data; } //important part
tmp2=tmp->next;
delete tmp;
tmp=tmp2;
}
}
};
The important part is the isDelete
This is only a sample code
I need this because I want to store data like this:
GenericList<int> list;
list.add(22);list.add(33);
and also
GenericList<string*> list;
list.add(new string("asd")); list.add(new string("watta"));
The problem if I store only <int> the compiler said that I cannot delete non pointer variables, but I don't want to in this case. How can I solve this?
when I store <int*> there is no compiler error...

Without changing much your code, I would solve your problem as
template<class t>
class GenericList
{
//same as before
//add this function template
template<typename T>
void delete_if_pointer(T & item) {} //do nothing: item is not pointer
template<typename T>
void delete_if_pointer(T* item) { delete item; } //delete: item is pointer
~GenericList() {
c_list* tmp = first;
c_list* tmp2;
while(tmp->next!=NULL) {
delete_if_pointer(tmp->data); // call the function template
tmp2=tmp->next;
delete tmp;
tmp=tmp2;
}
}
};
EDIT: I just noticed that #ildjarn has provided similar solution. However there is one interesting difference: my solution does NOT require you to mention the type of data when calling the function template; the compiler automatically deduces it. #ildjarn's solution, however, requires you to mention the type explicitly; the compiler cannot deduce the type in his solution.

I would create a nested struct template inside your class to help:
template<typename U>
struct deleter
{
static void invoke(U const&) { }
};
template<typename U>
struct deleter<U*>
{
static void invoke(U* const ptr) { delete ptr; }
};
Then change the line that was using isDelete from
if (isDelete) { delete tmp->data; }
to
if (isDelete) { deleter<t>::invoke(tmp->data); }

delete on an int makes a program ill-formed, so the compiler will reject it, even though the delete would never be reached.
What you want is only possible if you switch from "bare" pointers to smart pointers such as unique_ptr or shared_ptr; those handle memory management for you, without explicit delete.

Related

deleting a object by calling a method it belongs

I have been learning and playing around C++ (mostly, pointers and dynamic memory allocation) for few days and I tried to create a generic class for linked list.
The classes
#include <cstdint>
#define _LINKEDLIST_DEFAULT_MAX_SIZE 2147483647L
template <typename T>
class LinkedList;
template <typename T>
class LinkedListNode;
template <typename T>
class LinkedListNode final
{
private:
LinkedListNode<T> *nextNode{nullptr};
friend LinkedList<T>;
public:
T data{};
};
template <typename T>
class LinkedList final
{
private:
LinkedListNode<T> *firstNode{nullptr};
std::int32_t maxLength{};
std::int32_t currentLength{};
public:
LinkedList(std::int32_t max_size = _LINKEDLIST_DEFAULT_MAX_SIZE)
{
maxLength = max_size;
}
void addFirst(LinkedListNode<T> *nodePtr)
{
if (firstNode == nullptr)
{
firstNode = nodePtr;
return;
}
nodePtr->nextNode = firstNode;
firstNode = nodePtr;
}
void clerList()
{
// code of releasing occupied heap memory back
}
}
Main method
int main()
{
LinkedList<short> *head{new LinkedList<short>()};
LinkedListNode<short> *node1{new LinkedListNode<short>()};
LinkedListNode<short> *node2{new LinkedListNode<short>()};
node1->data = 1;
node2->data = 2;
head->addFirst(node1);
head->addFirst(node2);
return 0;
}
And this works as properly so far as variables in my debugger shows expected results.
But my issue is how could I write my clearList() method on LinkedList<T> class? I can traverse through LinkedListNode<T> objects and release their memory back calling delete(), but calling delete(this) from clearList() to release back the memory of LinkedList<T> object at first sounds like suiciding since it tries to delete the object which it belongs to. (Note that some simple validation logics have not yet been put into the code)
Do you have any ideas to make this happen :)

How can I detect that a template is of pointer type?

I have a couple of problems in my code. The first is in the variable "Element" and it works well for me as long as the constructor of the class that sent the template its variables have default values, is there a way to skip the constructor without putting defaults values in the class? And the other problem is when it comes to freeing memory, when T is of the pointer type I will need to do the delete but just as I put the code I get an error, is there any other solution that can help me? I will be attentive to your answers, thanks: D
namespace Linked{
template <class T>
struct Nodo{
const bool isponter = is_pointer<T>::value;
T Element;
Nodo<T> *Next;
Nodo(){
this->Next = nullptr;
}
~Nodo(){
if(is_pointer<T>::value)
delete Element;
}
};
}
namespace Linked{
template <class T>
struct Nodo{
T Element;
Nodo<T> *Next = nullptr;
~Nodo(){
if constexpr (std::is_pointer<T>::value)
delete Element;
}
};
You should also consider if T is pointer to array.
The only syntactial problems with your code are, that you didn't #include <type_traits> and forgot the std:: before is_pointer<T>::value.
But what you are attempting to do will raise problems with ownership. When Nodo contains a pointer it shouldn't own the object that pointer is pointing to. So you can't just delete that pointer, since you can't even know where it is pointing. Consider the following three cases, each of them requires different handling, but you have no way of determining what case you are facing:
Nodo<int*> n1, n2, n3;
n1.Element = new int(1); // requires delete
n2.Element = new int[10]; // requires delete[], crashes with delete
int i = 0;
n3.Element = &i; // no delete at all, crashes with delete
Usually whoever allocated a object on the heap is responsible for deallocating it. Nodo should not attempt to deallocate memory which it hasn't allocated.
As you didn't specify a c++ version, I'm gonna assume you use the latest, which now is C++17. The closest fit to your existing code is using if constexpr, I won't elaborate on that as there are other good answers for that. If you are stuck on C++14 or C++11 (or worse 03/98, in which case you should simply upgrade), you will need to specialize your template. (I'll come back to this)
This code however, is violating one of the CppCoreGuidelines: ES.24: Use a unique_ptr<T> to hold pointers By writing your template to detect raw pointers and delete it, one always has to allocate. Hence your linked list can't refer to some sub-data of something existing. As already eluded to in the comments, if the users want the memory to be cleaned, use std::unique_ptr. An example:
namespace Linked{
template <class T>
struct Nodo{
T Element;
Nodo<T> *Next{nullptr};
Nodo() = default;
~Nodo() = default;
};
}
// Has ownership
auto node = Nodo<std::unique_ptr<int>>{};
node.element = std::make_unique<int>(42);
// Has ownership (to array of 42 elements)
auto node = Nodo<std::unique_ptr<int[]>>{};
node.element = std::make_unique<int[]>(42);
// No ownership
int value = 42;
auto node = Nodo<int>{};
node.element = &value;
With this, ownership is clear to the caller and transparant for you. (as you don't need to know about arrays, std::unique_ptr knows about that) You might want to put some restrictions on T, like adding static_assert(std::is_nothrow_move_constructable<T>);.
This above solution solves the problem in C++11 and upwards and should be the recommended approach.
If not, use if constexpr if your condition isn't capturable in a dedicated class in C++17. And partial specialization in C++14 and C++11.
namespace Linked{
template <class T>
struct Nodo{
T Element;
Nodo<T> *Next{nullptr};
Nodo() = default;
~Nodo() = default;
};
template <class T>
struct Nodo<T*>{
T *Element{nullptr};
Nodo<T> *Next{nullptr};
Nodo() = default;
~Nodo() { delete Element; }
};
}
If you don't want to repeat your code too much
namespace Linked{
template <class T, class Me>
struct AbstractNodo{
T Element;
Me *Next{nullptr};
// All common code
};
template <class T>
struct Nodo : AbstractNodo<T, Nodo<T>>{
Nodo() = default;
~Nodo() = default;
};
template <class T>
struct Nodo<T*> : AbstractNodo<T, Nodo<T*>>{
Nodo() = default;
~Nodo() { delete Element; }
};
}
There is also a way to specialize a single method, however, I'm not that familiar with it, see Stack overflow: Template specialization of a single method from a templated class for more details.

Creating a Node for a Linked List where the Data Lacks a Default Constructor

I am trying to implement a class that represents a doubly-linked list, and I have a function createNode() which returns a new Node (A templated class) with all its members initialized. This function is going to be used to create linked lists where the size is known, but no data has been passed to it. For most data types, this works. However, this does not work for classes without default constructors, since they cannot be initialized without parameters. Here is the minimal code that exhibits this:
class Test // A class without a default constructor
{
public:
Test(int value) : value_{ value } { };
private:
int value_;
};
template<typename T>
struct Node
{
Node* prev;
Node* next;
T value;
};
template<typename T>
Node<T>* createNode()
{
return new Node<T>{ nullptr, nullptr, T() }; // How do I change T() so
// that I can use classes
// without default constructors?
}
int main()
{
Node<Test>* testNode = createNode<Test>();
delete testNode;
}
Basically, my final goal is to be able to create a linked list which can hold uninitialized nodes while keeping track of which nodes are initialized or not. I remember reading in an old textbook of mine about a method for solving this problem that involves using allocators (Which are used for handling construction/destruction of objects), but I don't remember the exact technique at all. So how should I go about this?
Use std::optional<T> if you have access to C++17, or boost::optional<T> if you don't.
template<typename T>
struct Node
{
Node* prev;
Node* next;
std::optional<T> value; // or boost::optional<T> value;
};
template<typename T>
Node<T>* createNode()
{
return new Node<T>{ nullptr, nullptr, std::nullopt /* or boost::none */ };
}
If you don't have access to C++17 and don't want to include boost, you could roll your own optional template with something like this:
struct nullopt_t {};
nullopt_t nullopt;
template <typename T>
class optional
{
public:
template <typename... Args>
optional(Args&&... args)
: ptr{new ((void*)&storage) T(std::forward<Args>(args)...)}
{}
optional(nullopt_t)
: ptr{nullptr}
{}
~optional()
{
if (ptr) {
ptr->~T();
}
}
optional& operator=(T obj)
{
if (ptr) {
*ptr = std::move(obj);
} else {
ptr = new ((void*)&storage) T(std::move(obj));
}
return *this;
}
explicit operator bool()
{
return ptr != nullptr;
}
T& value()
{
if (!ptr) {
throw std::exception();
}
return *ptr;
}
// Other const-correct and rvalue-correct accessors left
// as an exercise to the reader
private:
std::aligned_storage_t<sizeof(T), alignof(T)> storage;
T* ptr;
};
Live Demo
You can use placement new to place the object later in a pre-allocated memory.
It's just about splitting the memory allocation from the construction of the objects. So you can declare a member in your Node that takes memory but do not construct object because it needs parameter. Later you can construct the object with the needed parameters but not allocate memory with new but use placement new to just call the constructor with memory already allocated within the Node.
So following is an example of a self-made std::optional. In n3527 you can find more details about std::optional.
#include <vector>
#include <functional>
#include <iostream>
#include <algorithm>
#include <string>
#include <memory>
using namespace std;
class Test // A class without a default constructor
{
public:
Test(int value) : value_{ value } { };
//private:
int value_;
};
template<typename T>
struct Node
{
Node* prev;
Node* next;
bool empty = true;
union {
T t;
} value; // Could be replaced with typename std::aligned_storage<sizeof(T), alignof(T)>::type value;
// need a constructor that inits the value union and activate a field
// Node()
~Node() {
if (!empty) {
value.t.~T();
}
}
template<typename... Args>
void setValue(Args... args) {
if (!empty) {
value.t.~T();
}
new (&value.t) T(std::forward<Args...>(args...));
empty = false;
}
T& getValue() {
// TODO:
if (empty) {
//throw
}
return value.t;
}
};
template<typename T>
Node<T>* createNode()
{
return new Node<T>{ nullptr, nullptr }; // How do I change T() so
// that I can use classes
// without default constructors?
}
int main()
{
Node<Test>* testNode = createNode<Test>();
testNode->setValue(42);
if (!testNode->empty) {
std::cout << testNode->getValue().value_;
}
delete testNode;
return 0;
}
Live Demo
With few small changes and with reinterpret_cass you can also use typename std::aligned_storage<sizeof(T), alignof(T)>::type value; - Live Demo
Allocators manage the memory and you will not be able include (aggregate) the object in your class and have to use pointers and second allocation except you use allocator to place the entire Node.
There are interesting presentation form John Lakos about allocators on YouTube - CppCon 2017 Local 'Arena' Memory Allocators part 1 and 2.
What you are asking is literally impossible -- to default construct an object without a default constructor.
Perhaps consider adding a T nodeValue parameter to createNode()? Or change the Node itself so that rather than holding an object, it holds a pointer to the object. That seems like a memory management nightmare, but it could work.

C++ Templated linked list getting data element of a complex data type

I've been working on updating my old templated linked list to be able to take a complex data type. But I have no idea how to make it be able to return the data element in the node class. Currently the code for my node class looks like this:
using namespace std;
#ifndef Node_A
#define Node_A
template <class T>
class Node
{
public:
Node();
~Node();
T getData();
Node* getNext();
void setData(T);
void setNext(Node*);
private:
Node *next;
T data;
};
template <class T>
Node<T>::Node()
{
next = NULL;
return;
}
template <class T>
Node<T>::~Node()
{
return;
}
template <class T>
T Node<T>::getData()
{
return data;
}
template <class T>
Node<T>* Node<T>::getNext()
{
return next;
}
template <class T>
void Node<T>::setData(T a)
{
data = a;
return;
}
template <class T>
void Node<T>::setNext(Node* a)
{
next = a;
return;
}
#endif
Now this works perfectly fine if the data type T is a primitive but if you use a non-primitive like say a struct it would give a runtime error. I presume because structs don't do operator overloading for = operator. Is there a simple way of fixing this without completely overhauling the class?
It's not about overloading the = operator, it's about implementing the assignment operator for the struct. If you do that, you won't need to change your Node class, unless I've missed something else.
The above assumes that you'll be making copies of the data inside the Node. Alternatively, you can pass the data by reference. In this case, you need to be careful that the data doesn't get deleted before the Node object is deleted, otherwise you'll get a crash when trying to access a deleted data object from your Node.

C++ -- determine if generic variable is a pointer

I have a class, which I'll refer to as myclass, that has a list container of the type T. I also have a couple of methods that remove items from the list. Should the T be a pointer of some sort, I would like to check that it indeed is a pointer and then delete it in order to relieve allocated resources back to memory. Here's a snippet of code:
template<typename T>
class myclass{
private:
std::list<T> * container;
// other vars
public:
void erase(const T &item){
if (!this->find(item)) // find is defined elsewhere
return false;
auto temp = container->begin();
for (int i = 0; i < container->size(); ++i){
// this is where i would like to check if *temp is a pointer,
// so that I can assign it to a pointer var, remove it from the list,
// then delete the pointer,
//otherwise just simply remove it from the list.
}
}
};
EDIT
auto temp = container->begin();
I want to know how to determine if *temp is a pointer so that I can do the following:
T * var = *temp;
container->remove(temp); // remove or erase, i can't recall at the moment
delete var;
but I only want to do that if *temp is a pointer
1) Determine if Type is a pointer in a template function
2) How would you know if that pointer is pointing to dynamically allocated memory?
I don't think this is a wise idea. You don't know whether the user has provided pointers to data allocated on the stack, or to data that is managed in some other way (eg with smart pointers).
But to answer the question, look at
std::is_pointer<T>::value // in type_traits header
http://en.cppreference.com/w/cpp/types/is_pointer
This is a C++11 feature.
Sorry, but no: std::list<T>::iterator (which is what begin() will return and therefore will be the type of temp) can't ever be a pointer. It must be a type that (at the very least) overloads pre- and post-increment and decrement to do linked list traversal so ++ will do something like pos = pos->next; and -- will to something like pos = pos->prev;.
If you're trying to figure out if *temp (which will be the same type as T) is a pointer, that's a whole different story. You basically have two routes. The one I'd prefer as a general rule would be to provide a specialization of your class for pointers:
template<typename T>
class myclass{
private:
std::list<T> container;
// other vars
public:
void erase(const T &item){
if (!container->find(item)) // find is defined elsewhere
return false;
auto temp = container->begin();
for (int i = 0; i < container->size(); ++i){
container.erase(temp);
}
}
};
template<class T>
class myclass <T *> {
private:
std::list<T> container;
// other vars
public:
void erase(const T &item){
if (!container->find(item)) // find is defined elsewhere
return false;
auto temp = container->begin();
for (int i = 0; i < container->size(); ++i){
delete *temp;
container.erase(temp);
}
}
};
The biggest problem with this is that you may end up duplicating a fair amount between the base template and the specialization for pointers. There are a couple of ways of avoiding that. One is to use a base class that implements the common behavior, then derive the two specializations from that to provide the specialized behavior. Another would be to use some enable_if or SFINAE to enable different versions of the erase function depending on whether the contained type is something that can be dereferenced or not.
As an aside, you probably shouldn't have std::list<T> *container; -- it should probably be just std::list<T> container; (or, better still in most cases, std::vector<T> container;)
Isn't it annoying container's don't delete normal pointers? Well in C++ raw pointers don't actually own the object. There could be many pointers pointing to the same object. You need a unique pointer - stl provides one in c++11. When a unique_ptr is removed from the list, it will destroy the object it points to, so there is no need to complicate erase.
#include <list>
#include <memory>
#include <type_traits>
using namespace std;
template<typename t, bool b>
struct Selector {
typedef list<T> container;
};
template<typename t>
struct Selector<t, true> {
typedef list<unique_ptr<T> > container;
};
template<typename T>
class myclass{
private:
Selector<T, is_pointer<T>::value>::container* container;
// other vars
public:
void erase(const T &item){
if (!this->find(item)) // find is defined elsewhere
return false;
auto temp = container->begin();
for (int i = 0; i < container->size(); ++i){
// removing the unique_ptr delete's pointer
}
}
};