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
}
}
};
Related
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.
I've created a Node struct to be used in an implementation of binary search tree. It uses shared pointers to keep track of its children:
template <class T> struct Node;
template <class T>
using Node_ptr = std::shared_ptr<Node<T>>;
template <class T>
struct Node {
Node_ptr<T> left;
Node_ptr<T> right;
const T label;
...
};
Now, I'd like to have a function which given some subtree and a value will return either the node of that specific value or the place where such node should be located in future - find_node.
This is how it looks at the moment:
template <class T>
auto* find_node(Node_ptr<T>* node, const T& value) {
for (; *node && (*node)->label != value
; node = value < (*node)->label ? &(*node)->left : &(*node)->right);
return node;
}
Pretty bad. But it works:
template <class T>
class Binary_search_tree {
public:
// correctly inserts consecutive values
void insert(const T& value) {
if (auto* node = find_node(&root, value); !*node)
*node = std::make_shared<Node<T>>(value);
}
...
private:
Node_ptr<T> root;
...
};
I could rewrite find_node to use std::shared_ptr<Node_ptr<T>> instead of Node_ptr<T>* but it would look even worse. Or would it?
How should I handle such situations?
edit: As it's been pointed out, the function can be simplified a bit by taking a reference to starting node, and returning a reference to a node:
template <class T>
Node_ptr<T>& find_node(Node_ptr<T>& node_ref, const T& value) {
auto* node = &node_ref;
...
return *node;
}
Use of a raw pointer is suggested when you have to allow for passing a null pointer - not true in your example; or when you have to pass a non-integral value (true in your case). In the latter case one should still consider passing a reference rather than a raw pointer. This is a generic suggestion - so exceptions may exist.
Having noted that, you could still use a raw pointer in your function here rather safely by making find_node(...) a private function while keeping the insert(...) public. That is safe, since there is no chance of leaving the pointer dangling from inside insert(...).
Essentially we need to guard against two possibilities with raw pointers: #1. prematurely deleting the memory the pointer points to, #2. never deleting the memory that the pointer points to. Neither of this is possible inside your insert(...) function. So you're safe.
On a related note, you might consider having unique_pointer for your nodes when they are created and then converting them into shared pointers if they are to be shared by more child than one: std::move(...).
I'm trying to give my generic list class a reverse function. For some reason, my algorithm ain't workin' when I test it. I thought it made sense: swap the pointers to the first and last nodes of the list, then go through the list and for each node swap its pointers to the previous and next node.
Go easy on me, guys. I'm trying to get some practice with generic programming. Teach me the ways of a C++ purist.
Here's the swap function:
template <class T> void swap(T* a, T* b) {
T* tempPtr = a;
a = b;
b = tempPtr;
}
Here's the reverse function:
template <class T> void List<T>::reverse() {
if (size > 1) {
swap(firstNodePtr, lastNodePtr);
node* curNodePtr = firstNodePtr;
while (curNodePtr != NULL) {
swap(curNodePtr->prevNodePtr, curNodePtr->nextNodePtr);
curNodePtr = curNodePtr->nextNodePtr;
}
}
}
Here's the class, its members and prototypes for functions:
template <class T> class List {
public:
List();
~List();
void push_back(T);
void push_front(T);
T get_at(unsigned);
unsigned get_size();
void reverse();
private:
struct node {
T val;
node* prevNodePtr;
node* nextNodePtr;
};
node* firstNodePtr;
node* lastNodePtr;
unsigned size;
};
Your swap<T> function does not work: it exchanges pointers, which are copied by value into local variables of your function, which has no effect in the caller.
Dropping your own swap and replacing it with std::swap will fix this problem.
Since you pass the two pointers by value, the changes to a and b don't propagate out of the swap() function, making it a no-op.
One way to fix it is by passing the pointers by reference:
template <class T> void swap(T*& a, T*& b) {
Alternatively (and preferably) just use std::swap() instead of your own function.
If you exposed your node structure (or at least a bidirectional iterator type for your list), you could avoid the whole issue and just use std::reverse.
List<int> someList;
// fill with data
std::reverse(someList.begin(), someList.end()); // where begin returns a bidirectional iterator for the head, and end returns a bidirectional iterator for 1 element beyond the tail
As an example, consider a simple data structure like a linked list. In C, it might look like:
struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
I'd like to have the same struct and functions, but with better type checking by declaring the type of the data field, which will always be a pointer to something. An example use:
Node<Thing*> list = getListOfThings();
Thing *t = list->data;
t = getLastItem(list);
...
But I don't want to generate an implementation for every type of pointer, as happens with a normal template. In other words, I want something more like a generic or parametric type from Java, ML, and other languages. I just tried the code below as a test. The untyped C-like part would eventually go in a implementation file, while the template and function declarations would be in the header file. I'm assuming they would be optimized away and I'd be left with machine code that is about the same as the C version, except it would be type-checked.
But I'm not great with C++... Is there a way to improve this, or use more idiomatic C++, perhaps template specialization?
#include <stdio.h>
struct NodeImpl
{
NodeImpl *next;
void *data;
};
void *getLastItemImpl(NodeImpl *list)
{
printf("getLastItem, non-template implementation.\n");
return 0; // not implemented yet
}
template <typename T>
struct Node
{
Node<T> *next;
T data;
};
template <typename T>
T getLastItem(Node<T> *list)
{
return (T)getLastItemImpl((NodeImpl*)list);
}
struct A { };
struct B { };
int main()
{
Node<A*> *as = new Node<A*>;
A *a = getLastItem(as);
Node<B*> *bs = new Node<B*>;
B *b = getLastItem(bs);
}
This is exactly what Boost.PointerContainer does, check its implementation. Basically what it does is implement the specialization for void*, and have any other implementation forward to it static_casting the parameters in and out.
struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
This is common for C, but not for C++. In C++ it usually looks like this:
template<typename T>
struct Node
{
struct Node *next;
T data;
};
T& getLastItem(const Node&);
...
Note the important difference -- the C version has another level of indirection in order to share implementations, while the C++ version need not do this. This means the C version has another n dynamic memory allocations, where n is the number of items in the list. Given that each allocation usually requires obtaining a global lock, often has at least 16 bytes of overhead per allocation, as well as all the overhead the memory manager brings to the party, the advantage of the C++ version is not insignificant, particularly when you include things like cache locality in the considerations.
Put another way, for Node<int>, the C++ version stores an int, while the C version stores an int *, along with a dynamic allocation for the int.
This of course discounting that a linked list is a horrendous data structure 90% of the time.
If you must use a linked list, and if you must use dynamic allocation for the data members, then your idea of "replace the pointers with void*s" is not unreasonable. However, if you have access to a C++11 compiler (VS2010, recent GCC versions, etc.), you should put in an assert that you depend on T being a pointer type, using std::is_pointer and static_assert, and you should use static_cast rather than C-style casts in your interface methods. The C style cast would let someone do Node<SomeTypeBiggerThanVoidPtr>, and it would compile, but explode at runtime.
As the other answers and comments said, use std::forward_list, or another existing library. If you refuse, this is more like I would do:
#include <stdio.h>
struct NodeImpl
{
NodeImpl *next;
void *data;
public:
// we have pointers, so fulfill the rule of three
NodeImpl() : next(NULL), data(NULL) {}
~NodeImpl() {}
NodeImpl& operator=(const NodeImpl& b) {next = b.next; data = b.data; return *this;}
// This function now a member. Also, I defined it.
void* getLastItem()
{
if (next)
return next->getLastItem();
return data;
}
void* getData() {return data;}
void setData(void* d) {data = d;}
};
// the template _inherits_ from the impl
template <typename T>
struct Node : public NodeImpl
{
Node<T> operator=(const Node<T>& b) {NodeImpl::operator=(b);}
// we "redefine" the members, but they're really just wrappers
T* getLastItem()
{ return static_cast<T*>(NodeImpl::getLastItem());}
T* getData() {return static_cast<T*>(NodeImpl::getData());}
void setData(T* d) {NodeImpl::setData(static_cast<void*>(d));}
//or, if you prefer directness...
operator T*() {return static_cast<T*>(NodeImpl::getData());}
Node<T> operator=(T* d) {NodeImpl::setData(static_cast<void*>(d));}
};
struct A { };
struct B { };
int main()
{
Node<A> as; //why were these heap allocated? The root can be on the stack
A *a = as.getLastItem();
Node<B> bs; //also, we want a each node to point to a B, not a B*
B *b = bs.getLastItem();
B* newB = new B;
bs = newB; //set the data member
newB = bs; //read the data member
}
http://ideone.com/xseYk
Keep in mind that this object doesn't encapsulate next or data really, so you have to manage all of that yourself.
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.