2

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

czifro
  • 784
  • 7
  • 24
  • 3
    i would recommend only letting users do myclass> rather than pointers - you don't really now when the user wnats to deallocate a raw pointer, and a smart pointer will deallocated itself – user3125280 Dec 30 '13 at 03:37
  • std::is_pointer? would that be used like such: `if (std::is_pointer(pointer))` ? – czifro Dec 30 '13 at 03:41
  • 1
    `std::is_pointer<>` is a template *type* conditional. I.e. `std::is_pointer::value`, and regardless, I'm with most of the opinions on this; doing this is not entirely sound. – WhozCraig Dec 30 '13 at 03:53
  • Regarding your edit: `*temp` is a pointer if and only if `T` is a pointer type. In the case of `*temp` and `T` being pointer types `T*` would be pointer to pointer type and the line `T* var = *temp` would cause a compilation error. You should just do `delete *temp`. Notice however, that even if `*temp` is a pointer it is not guaranteed that it points to allocated memory and `delete` might cause an error. –  Dec 30 '13 at 03:58

4 Answers4

2

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.

NicholasM
  • 4,557
  • 1
  • 20
  • 47
2

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;)

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 2
    You answered the precise question in the questioner's code, but missed the point. The questioner wants to know if the list elements are pointers, not whether std::list interators are pointers. He made a mistake in asking about temp, instead of *temp. – NicholasM Dec 30 '13 at 03:45
  • I do realize begin() returns an iterator. And I decided to use a list because it has an insertion complexity of O(1). I guess what I getting at is, should someone utilize my class as a container, i.e. myclass, then list would be containing string pointers. Is it possible to now that *it is a pointer to a string? that way I could do the following: `string * var = *it;` and then `delete var;` – czifro Dec 30 '13 at 03:48
2

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?

Community
  • 1
  • 1
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
0

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
        }
    }
};
user3125280
  • 2,779
  • 1
  • 14
  • 23