I am creating a datastructure that uses unique_ptr. I now want to define different iterators over this datastructure, however the nodes of my data structure are part of the data itself. Because of this I want the iterators to return the actual nodes and not only the values contained within.
Here is what I got so far (much simplified example):
#include <algorithm>
#include <iostream>
#include <memory>
using namespace std;
template <typename T> struct node {
node(T val) : val(val), next(nullptr) {}
node(T val, unique_ptr<node<T>> &n) : val(val), next(move(n)) {}
T val;
unique_ptr<node<T>> next;
template <bool Const = true> struct iter {
using reference =
typename std::conditional<Const, const node<T> *, node<T> *>::type;
iter() : nptr(nullptr) {}
iter(node<T> *n) : nptr(n) {}
reference operator*() { return nptr; }
iter &operator++() {
nptr = nptr->next.get();
return *this;
}
friend bool operator==(const iter &lhs, const iter &rhs) {
return lhs.nptr == rhs.nptr;
}
friend bool operator!=(const iter &lhs, const iter &rhs) {
return lhs.nptr != rhs.nptr;
}
node<T> *nptr;
};
iter<> begin() const { return iter<>(this); }
iter<> end() const { return iter<>(); }
iter<false> begin() { return iter<false>(this); }
iter<false> end() { return iter<false>(); }
};
template <typename T> void pretty_print(const unique_ptr<node<T>> &l) {
auto it = l->begin();
while (it != l->end()) {
auto elem = *it;
cout << elem->val << endl;
++it;
}
}
int main() {
auto a = make_unique<node<int>>(4);
auto b = make_unique<node<int>>(3, a);
auto c = make_unique<node<int>>(2, b);
auto d = make_unique<node<int>>(1, c);
for (auto *elem : *d) {
elem->val = elem->val - 1;
}
pretty_print(d);
return 0;
}
Is it considered bad practice to expose the raw pointers to the elements of the datastructure in this way? Will this work in a more complex example, especially in regard to const-correctness?
This is largely opinion, but I'd say it's a bad idea. unique_ptrs should be unique; the rare exceptions should be if you need to pass a raw pointer to some other function that isn't properly templated (and you know for a fact it doesn't hold on to the pointer).
Otherwise, you're in a situation where reasonable uses, e.g. initializing to a std::vector<node<int>*> using your iterator, violate the assumptions baked into unique_ptr. In general, you want your APIs to behave predictably with limited developer headaches, and your proposal adds the headache of "You can iterate it as long as you don't store anything to anything with a lifetime beyond my custom structure's lifetime".
Better options are:
Returning references to your actual unique_ptrs (so people are able to work with them without violating the uniqueness contract; make them const if they shouldn't be mutated); they'd have to take ownership or explicitly use "borrowed" unmanaged pointers at their own risk to store the results, but iteration would work fine and they can't accidentally violate uniqueness guarantees
Store shared_ptrs internally, and hand out new shared_ptrs during iteration, so ownership is automatically shared and lifetime extends as long as a single shared pointer remains
Importantly, neither of these two options allows someone to accidentally "do the wrong thing". The caller can do bad things, but they have to personally, explicitly bypass the smart pointer protection mechanisms to do so, and that's on their head.
Of course, the third option is:
Return a reference to the value pointed to, not the pointer; if the value is stored it should be copy-constructed
It's possible for users to get this last one wrong (by storing the reference long term, taking the address of it to get a new pointer violating uniqueness guarantees, etc.), but it follows existing C++ conventions (as Ryan points out in the comments) for containers like std::vector, so it's not a new concern; C++ developers generally know not to do terrible things with references acquired from iteration. It's arguably the best option, since it maps well to the standard patterns, making it easier for developers by fitting into existing mental models.
I would use reference instead of pointer in your iterator
using reference =
typename std::conditional<Const, const node<T>&, node<T>&>::type;
So your iterator has only to be dereferencing once.
(I would keep pointer for the member though).
Pointer in (public) interface introduce a doubt about ownership.
The usage syntax would be:
for (auto& elem : *d) {
elem.val = elem.val - 1;
}
or
while (it != l->end()) {
const auto& elem = *it;
std::cout << elem.val << std::endl;
++it;
}
Your iterator indeed is invalidated when its corresponding node is released which is the common case.
Related
I want to access my iterator class by reference
#include <iostream>
template <typename T> class binary_tree;
template <typename T>
class binary_tree_iterator {
private:
binary_tree<T>* tree;
T data;
public:
binary_tree_iterator(binary_tree<T>* t) : tree(t) {}
T& operator*() {data = tree->data(); return data;}
binary_tree_iterator& operator++() {tree = tree->get_node(); return *this;}
bool operator!=(binary_tree_iterator& rhs) {return tree->data() != rhs.tree->data();}
};
template <typename T>
class binary_tree {
private:
T t_data;
binary_tree<T>* node;
binary_tree_iterator<T>* It;
public:
binary_tree(T d) : t_data(d), node(nullptr), It(nullptr)
{}
T& data() {
return t_data;
}
void set_node(binary_tree<T>* node) {
this->node = node;
}
binary_tree<T>* get_node() {
return node;
}
binary_tree_iterator<T> begin() {
It = new binary_tree_iterator<T>(this);
return *It;
}
binary_tree_iterator<T> end() {
if(node == nullptr) {
It = new binary_tree_iterator<T>(this);
return *It;
} else {
return node->end();
}
}
};
int main() {
binary_tree<int>* tree = new binary_tree<int>(2);
tree->set_node(new binary_tree<int>(3));
//for(auto& x: *tree) <--- does not work
for(auto x: *tree) {
std::cout << x << std::endl;
}
}
The for-range loop I want to use it in looks something like for(auto& x: *tree). How do I give it a reference? Is there a standard way of doing this when creating iterators? When I return the data value I assign it to a iterator data member so I can return by reference. Will I have to do the same with my iterator? I don't imagine this is the standard way of doing this.
I want to access my iterator class by reference
How do I give it a reference?
By changing the return type of the function to be binary_tree_iterator<T>& instead of binary_tree_iterator<T>. If you do that, you'd have to store an iterator somewhere instead of returning a new one, so that you can refer to it. Presumably, it would have to be stored as a member variable.
Is there a standard way of doing this when creating iterators?
No. None of the standard containers return references to iterators.
I don't imagine this is the standard way of doing this.
Indeed. The "standard" i.e. conventional thing to do is to not return references to iterators.
The for-range loop I want to use it in looks something like for(auto& x: *tree)
There is no need to return a reference to an iterator in order to make that work. If you take a look at standard containers, you'll find that none of them return a reference to an iterator, and such loop works with all of them.
The reference in that loop is bound to the result of indirection through the iterator. So, it is the operator* that must return a reference to the pointed object. And, your operator* does indeed return a reference. That said, normally an iterator would return a reference to the object stored in the container; not a reference to copy stored in the iterator. So, that's highly unconventional.
Finish writing your iterator, and you'll find that the loop works.
In conclusion: You don't need to return iterator by reference, and you shouldn't.
I'm trying to define a good design for my software which implies being careful about read/write access to some variables. Here I simplified the program for the discussion. Hopefully this will be also helpful to others. :-)
Let's say we have a class X as follow:
class X {
int x;
public:
X(int y) : x(y) { }
void print() const { std::cout << "X::" << x << std::endl; }
void foo() { ++x; }
};
Let's also say that in the future this class will be subclassed with X1, X2, ... which can reimplement print() and foo(). (I omitted the required virtual keywords for simplicity here since it's not the actual issue I'm facing.)
Since we will use polymorphisme, let's use (smart) pointers and define a simple factory:
using XPtr = std::shared_ptr<X>;
using ConstXPtr = std::shared_ptr<X const>;
XPtr createX(int x) { return std::make_shared<X>(x); }
Until now, everything is fine: I can define goo(p) which can read and write p and hoo(p) which can only read p.
void goo(XPtr p) {
p->print();
p->foo();
p->print();
}
void hoo(ConstXPtr p) {
p->print();
// p->foo(); // ERROR :-)
}
And the call site looks like this:
XPtr p = createX(42);
goo(p);
hoo(p);
The shared pointer to X (XPtr) is automatically converted to its const version (ConstXPtr). Nice, it's exactly what I want!
Now come the troubles: I need a heterogeneous collection of X. My choice is a std::vector<XPtr>. (It could also be a list, why not.)
The design I have in mind is the following. I have two versions of the container: one with read/write access to its elements, one with read-only access to its elements.
using XsPtr = std::vector<XPtr>;
using ConstXsPtr = std::vector<ConstXPtr>;
I've got a class that handles this data:
class E {
XsPtr xs;
public:
E() {
for (auto i : { 2, 3, 5, 7, 11, 13 }) {
xs.emplace_back(createX(std::move(i)));
}
}
void loo() {
std::cout << "\n\nloo()" << std::endl;
ioo(toConst(xs));
joo(xs);
ioo(toConst(xs));
}
void moo() const {
std::cout << "\n\nmoo()" << std::endl;
ioo(toConst(xs));
joo(xs); // Should not be allowed
ioo(toConst(xs));
}
};
The ioo() and joo() functions are as follow:
void ioo(ConstXsPtr xs) {
for (auto p : xs) {
p->print();
// p->foo(); // ERROR :-)
}
}
void joo(XsPtr xs) {
for (auto p: xs) {
p->foo();
}
}
As you can see, in E::loo() and E::moo() I have to do some conversion with toConst():
ConstXsPtr toConst(XsPtr xs) {
ConstXsPtr cxs(xs.size());
std::copy(std::begin(xs), std::end(xs), std::begin(cxs));
return cxs;
}
But that means copying everything over and over.... :-/
Also, in moo(), which is const, I can call joo() which will modify xs's data. Not what I wanted. Here I would prefer a compilation error.
The full code is available at ideone.com.
The question is: is it possible to do the same but without copying the vector to its const version? Or, more generally, is there a good technique/pattern which is both efficient and easy to understand?
Thank you. :-)
I think the usual answer is that for a class template X<T>, any X<const T> could be specialized and therefore the compiler is not allow to simply assume it can convert a pointer or reference of X<T> to X<const T> and that there is not general way to express that those two actually are convertible. But then I though: Wait, there is a way to say X<T> IS A X<const T>. IS A is expressed via inheritance.
While this will not help you for std::shared_ptr or standard containers, it is a technique that you might want to use when you implement your own classes. In fact, I wonder if std::shared_ptr and the containers could/should be improved to support this. Can anyone see any problem with this?
The technique I have in mind would work like this:
template< typename T > struct my_ptr : my_ptr< const T >
{
using my_ptr< const T >::my_ptr;
T& operator*() const { return *this->p_; }
};
template< typename T > struct my_ptr< const T >
{
protected:
T* p_;
public:
explicit my_ptr( T* p )
: p_(p)
{
}
// just to test nothing is copied
my_ptr( const my_ptr& p ) = delete;
~my_ptr()
{
delete p_;
}
const T& operator*() const { return *p_; }
};
Live example
There is a fundamental issue with what you want to do.
A std::vector<T const*> is not a restriction of a std::vector<T*>, and the same is true of vectors containing smart pointers and their const versions.
Concretely, I can store a pointer to const int foo = 7; in the first container, but not the second. std::vector is both a range and a container. It is similar to the T** vs T const** problem.
Now, technically std::vector<T const*> const is a restriction of std::vector<T>, but that is not supported.
A way around this is to start workimg eith range views: non owning views into other containers. A non owning T const* iterator view into a std::vector<T *> is possible, and can give you the interface you want.
boost::range can do the boilerplate for you, but writing your own contiguous_range_view<T> or random_range_view<RandomAccessIterator> is not hard. It gets fancy ehen you want to auto detect the iterator category and enable capabilities based off that, which is why boost::range contains much more code.
Hiura,
I've tried to compile your code from repo and g++4.8 returned some errors.
changes in main.cpp:97 and the remaining lines calling view::create() with lambda function as the second argument.
+add+
auto f_lambda([](view::ConstRef_t<view::ElementType_t<Element>> const& e) { return ((e.getX() % 2) == 0); });
std::function<bool(view::ConstRef_t<view::ElementType_t<Element>>)> f(std::cref(f_lambda));
+mod+
printDocument(view::create(xs, f));
also View.hpp:185 required additional operator, namely:
+add+
bool operator==(IteratorBase const& a, IteratorBase const& b)
{
return a.self == b.self;
}
BR,
Marek Szews
Based on the comments and answers, I ended up creating a views for containers.
Basically I defined new iterators. I create a project on github here: mantognini/ContainerView.
The code can probably be improved but the main idea is to have two template classes, View and ConstView, on an existing container (e.g. std::vector<T>) that has a begin() and end() method for iterating on the underlying container.
With a little bit of inheritance (View is a ConstView) it helps converting read-write with to read-only view when needed without extra code.
Since I don't like pointers, I used template specialization to hide std::shared_ptr: a view on a container of std::shared_ptr<T> won't required extra dereferencing. (I haven't implemented it yet for raw pointers since I don't use them.)
Here is a basic example of my views in action.
A set of APIs that I commonly use follow a linked-list pattern:
struct SomeObject
{
const char* some_value;
const char* some_other_value;
SomeObject* next;
}
LONG GetObjectList( SomeObject** list );
void FreeObjectList( SomeObject* list );
This API is not mine and I cannot change it.
So, I'd like to encapsulate their construction/destruction, access, and add iterator support. My plan is to do something like this:
/// encapsulate access to the SomeObject* type
class MyObject
{
public:
MyObject() : object_( NULL ) { };
MyObject( const SomeObject* object ) : object_( object ) { };
const char* SomeValue() const
{
return NULL != object_ ? object_->some_value : NULL;
};
const char* SomeValue() const
{
return NULL != object_ ? object_->some_other_value : NULL;
};
private:
SomeObject* object_;
}; // class MyObject
bool operator==( const MyObject& i, const MyObject& j )
{
return // some comparison algorithm.
};
/// provide iterator support to SomeObject*
class MyObjectIterator
: public boost::iterator_adaptor< MyObjectIterator,
MyObject*,
boost::use_default,
boost::forward_traversal_tag >
{
public:
// MyObjectIterator() constructors
private:
friend class boost::iterator_core_access;
// How do I cleanly give the iterator access to the underlying SomeObject*
// to access the `next` pointer without exposing that implementation detail
// in `MyObject`?
void increment() { ??? };
};
/// encapsulate the SomeObject* creation/destruction
class MyObjectList
{
public:
typedef MyObjectIterator const_iterator;
MyObjectList() : my_list_( MyObjectList::Create(), &::FreeObjectList )
{
};
const_iterator begin() const
{
// How do I convert a `SomeObject` pointer to a `MyObject` reference?
return MyObjectIterator( ??? );
};
const_iterator end() const
{
return MyObjectIterator();
};
private:
static SomeObject* Create()
{
SomeObject* list = NULL;
GetObjectList( &list );
return list;
};
boost::shared_ptr< void > my_list_;
}; // class MyObjectList
My two questions are:
How do I cleanly give MyObjectIterator access to the underlying SomeObject to access the next pointer in the linked list without exposing that implementation detail in MyObject?
In MyObjectList::begin(), how do I convert a SomeObject pointer to a MyObject reference?
Thanks,
PaulH
Edit: The linked-list APIs I'm wrapping are not mine. I cannot change them.
First, of course, for real use, you almost certainly shouldn't be writing your own linked list or iterator at all. Second, good uses for linked lists (even one that's already written, debugged, etc.) are also pretty rare -- except in a few rather unusual circumstances, you should probably use something else (most often vector).
That said, an iterator is typically a friend (or nested class) of the class to which it provides access. It provides the rest of the world with an abstract interface, but the iterator itself has direct knowledge of (and access to) the internals of the linked list (or whatever container) to which it provides access). Here's a general notion:
// warning: This is really pseudo code -- it hasn't been tested, and would
// undoubtedly require a complete rewrite to even compile, not to mention work.
template <class T>
class linked_list {
public:
class iterator;
private:
// A linked list is composed of nodes.
// Each node has a value and a pointer to the next node:
class node {
T value;
node *next;
friend class iterator;
friend class linked_list;
public:
node(T v, node *n=NULL) : value(v), next(n) {}
};
public:
// An iterator gives access to the linked list.
// Operations:
// increment: advance to next item in list
// dereference: access value at current position in list
// compare: see if one iterator equals another
class iterator {
node *pos;
public:
iterator(node *p=NULL) : pos(p) {}
iterator operator++() {
assert(pos);
pos = pos->next;
return *this;
}
T operator*() { return pos->value; }
bool operator!=(iterator other) { return pos != other.pos; }
};
iterator begin() { return iterator(head); }
iterator end() { return iterator(); }
void push_front(T value) {
node *temp = new node(value, head);
head = temp;
}
linked_list() : head(NULL) {}
private:
node *head;
};
To work along with the algorithms in the standard library, you have to define quite a bit more than this tried to (e.g., typedefs like value_type and reference_type). This is only intended to show the general structure.
My advice: Trash this and use an existing slist<> implementation. IIRC, it will be in C++1x, so your compiler(s) might already support it. Or it might be in boost. Or take it from someplace else.
Wherever you get it from, what you get has all these problems already solved, is likely very well tested, therefore bug-free and fast, and the code using it is easily recognizable (looking at it many of us would immediately see what it does, because it's been around for a while and it's going to to be part of the next standard).
The last time I wrote my own list class was before the STL became part of the C++ standard library.
Ok, since you're stuck with the API you have, here's something that might get you started:
class MyObjectList
{
public:
typedef SomeObject value_type;
// more typedefs
class iterator {
public:
typedef SomeObject value_type;
// more typedefs
iterator(SomeObject* pObj = NULL)
: pObj_(pObj) {}
iterator& operator++() {if(pObj_)pObj_ = pObj_->next;}
iterator operator++(int) {iterator tmp(*this);
operator++();
return tmp;}
bool operator==(const iterator& rhs) const
{return pObj_ == rhs.pObj_;}
bool operator!=(const iterator& rhs) const
{return !operator==(rhs);}
value_type& operator*() {return pObj_;}
private:
SomeObject* pObj_;
};
class const_iterator {
public:
typedef SomeObject value_type;
// more typedefs
const_iterator(const SomeObject* pObj = NULL)
: pObj_(pObj) {}
iterator& operator++() {if(pObj_)pObj_ = pObj_->next;}
iterator operator++(int) {iterator tmp(*this);
operator++();
return tmp;}
bool operator==(const iterator& rhs) const
{return pObj_ == rhs.pObj_;}
bool operator!=(const iterator& rhs) const
{return !operator==(rhs);}
const value_type& operator*() {return pObj_;}
private:
const SomeObject* pObj_;
};
MyObjectList() : list_() {GetObjectList(&list_;);}
~MyObjectList() {FreeObjectList(list_);}
iterator begin() {return list_ ? iterator(list_)
: iterator();}
const_iterator begin() const {return list_ ? const_iterator(list_)
: const_iterator();}
iterator end () {return iterator(getEnd_());}
const_iterator end () const {return const_iterator(getEnd_());}
private:
SomeObject* list_;
SomeObject* getEnd_()
{
SomeObject* end = list_;
if(list_)
while(end->next)
end = end->next;
return end;
}
};
Obviously, there's more to this (for example, I believe const and non-const iterators should be comparable, too), but that shouldn't be hard to add to this.
From what you said, you probably have a BIG legacy code using your struct SomeObject types but you want to play nicely with new code and use iterators/stl containers.
If that's the case, you will not be able to (in an easy way) use your new created iterator in all the legacy code base, since that will be changing a lot of code, but, you can write a templated iterator that, if your structs follow the same pattern, having a next field, will work.
Something like this (I haven't tested nor compiled it, it's just an idea):
Suppose you have your struct:
struct SomeObject
{
SomeObject* next;
}
You will be able to create something like this:
template <class T>
class MyIterator {
public:
//implement the iterator abusing the fact that T will have a `next` field, and it is accessible, since it's a struct
};
template <class T>
MyIterator<T> createIterator(T* object) {
MyIterator<T> it(object);
return it;
}
If you implement your iterator correctly, you will be able to use all the STL algorithms with your old structs.
PS.: If you're in a scenario of some legacy code with this kind of structs, I do too, and I implemented this workaround. It works great.
You would make MyObjectIterator a friend of MyObject. I don't see any better way. And really I think it's reasonable that iterators get whatever special friend access is necessary for them to perform their duties.
You don't seem to have considered how and where your MyObject instance are going to be stored. Or perhaps that's what this question is coming out of. It seems like you would have to have a separate linked list of MyObjects in your MyObjectList. Then at least MyObjectList::begin() can just grab the first MyObject of your internal linked list of them. And if the only operations that may modify or rearrange this list only ever happen through the iterators you provide, then you can problem keep these lists in synch without too much trouble. Otherwise, if there are functions in the API you're using that take the raw SomeObject linked list and manipulate it, then you may have trouble.
I can see why you've tried to design this scheme, but having separate MyObjects that point to SomeObjects even through SomeObjects themselves make up the real list structure.... That is not an easy way to wrap a list.
The simplest alternative is just to do away with MyObject completely. Let your iterators work against SomeObject instances directly and return those when dereferenced. Sure that does expose SomeObject to the outside, particularly its next member. But is that really a big enough problem to justify a more complex scheme to wrap it all up?
Another way to deal with might be to have MyObject privately inherit from SomeObject. Then each SomeObject instance can be downcast as a reference to a MyObject instance and given to the outside world that way, thus hiding the implemtation details of SomeObject and only exposing the desired public member functions. The standard probably doesn't guarantee this will work, but in practice since they'll likely have the exact same memory layouts you may be able to get away with it. However, I'm not sure that I would actually ever try such a thing in a real program unless absolutely necessary.
The last alternative I can think of is just to transfer the data into a list of more convenient data structures after being given to you by this API. And then of course transfer it back into a raw SomeObject list only if necessary to pass it back to the API. Just make your own SomeObjectData or whatever to store the strings and put them in a std::list. Whether or not this is actually feasible for you really depends on how this data is used in the context of the API you've mentioned. If there are other API functions that modify SomeObject lists and you need to use them frequently, then constantly converting SomeObject lists to and from std::list<SomeObjectData> could be annoying.
I've seen some very good answers so far but I fear they might be "bare".
Before blindingly charge in let's examine the requirements.
As you noticed the structure is similar to a singly linked list, the C++0x standard defines such a structure, called forward_list. Read up its interface, yours should come close.
The iterator type will be ForwardIterator.
I would like to expose one very annoying fact though: who's responsible for the memory ?
I am worried because there's no copy facility in the interface you've provided, so should we disable the copy constructor and assignment operator of our new list class ?
Implementation is easy, there's enough on this page even though the iterator don't properly implement the iterator traits in general, but I would consider ditching this idea completely and move on to a better scheme:
class MyObject { public: ... private: SomeObject mData; };
Wrapping up GetObjectList and returning a deque<MyObject>, I guess the LONG returns the number of items ?
I have a huge tree where keys insides nodes are indices into a big hash_map v,
where v[key] is a (big) record associated with that key (includes how many nodes in the tree have this key). Right now, key is an integer. So each node
has overhead of storing pointers for children and an integer.
We can remove a key from a node in the tree.
We can't store the actual record in the tree node (because that would be a memory hog).
When a key is removed from a node, we need to look at v, update the count and remove the element
(and compact the vector).
This cries out for a smart pointer implementation: where we have a shared_ptr spread around the tree.
Once the last node that refers to key k is remove, the object is destroyed.
However, I am leery of the size requirements for shared_ptr. I need a cheep reference counted
smart counter. I don't care about concurrent access.
Here's a simple reference-counting smart pointer I picked off the web a few years ago and patched up a little:
/// A simple non-intrusive reference-counted pointer.
/// Behaves like a normal pointer to T, providing
/// operators * and ->.
/// Multiple pointers can point to the same data
/// safely - allocated memory will be deleted when
/// all pointers to the data go out of scope.
/// Suitable for STL containers.
///
template <typename T> class counted_ptr
{
public:
explicit counted_ptr(T* p = 0)
: ref(0)
{
if (p)
ref = new ref_t(p);
}
~counted_ptr()
{
delete_ref();
}
counted_ptr(const counted_ptr& other)
{
copy_ref(other.ref);
}
counted_ptr& operator=(const counted_ptr& other)
{
if (this != &other)
{
delete_ref();
copy_ref(other.ref);
}
return *this;
}
T& operator*() const
{
return *(ref->p);
}
T* operator->() const
{
return ref->p;
}
T* get_ptr() const
{
return ref ? ref->p : 0;
}
template <typename To, typename From>
friend counted_ptr<To> up_cast(counted_ptr<From>& from);
private: // types & members
struct ref_t
{
ref_t(T* p_ = 0, unsigned count_ = 1)
: p(p_), count(count_)
{
}
T* p;
unsigned count;
};
ref_t* ref;
private: // methods
void copy_ref(ref_t* ref_)
{
ref = ref_;
if (ref)
ref->count += 1;
}
void delete_ref()
{
if (ref)
{
ref->count -= 1;
if (ref->count == 0)
{
delete ref->p;
delete ref;
}
ref = 0;
}
}
};
Storage requirements per smart pointer are modest: only the real pointer and the reference count.
Why not just extend your tree implementation to keep track of counts for the keys stored within in? All you need then is another hashmap (or an additional field within each record of your existing hashmap) to keep track of the counts, and some added logic in your tree's add/remove functions to update the counts appropriately.
template <class Enum>
class EnumIterator {
public:
const Enum* operator-> () const {
return &(Enum::OfInt(i)); // warning: taking address of temporary
}
const Enum operator* () const {
return Enum::OfInt(i); // There is no problem with this one!
}
private:
int i;
};
I get this warning above. Currently I'm using this hack:
template <class Enum>
class EnumIterator {
public:
const Enum* operator-> () {
tmp = Enum::OfInt(i);
return &tmp;
}
private:
int i;
Enum tmp;
};
But this is ugly because iterator serves as a missing container.
What is the proper way to iterate over range of values?
Update:
The iterator is specialized to a particular set objects which support named static constructor OfInt (code snippet updated).
Please do not nit-pick about the code I pasted, but just ask for clarification. I tried to extract a simple piece.
If you want to know T will be strong enum type (essentially an int packed into a class). There will be typedef EnumIterator < EnumX > Iterator; inside class EnumX.
Update 2:
consts added to indicate that members of strong enum class that will be accessed through -> do not change the returned temporary enum.
Updated the code with operator* which gives no problem.
Enum* operator-> () {
tmp = Enum::OfInt(i);
return &tmp;
}
The problem with this isn't that it's ugly, but that its not safe. What happens, for example in code like the following:
void f(EnumIterator it)
{
g(*it, *it);
}
Now g() ends up with two pointers, both of which point to the same internal temporary that was supposed to be an implementation detail of your iterator. If g() writes through one pointer, the other value changes, too. Ouch.
Your problem is, that this function is supposed to return a pointer, but you have no object to point to. No matter what, you will have to fix this.
I see two possibilities:
Since this thing seems to wrap an enum, and enumeration types have no members, that operator-> is useless anyway (it won't be instantiated unless called, and it cannot be called as this would result in a compile-time error) and can safely be omitted.
Store an object of the right type (something like Enum::enum_type) inside the iterator, and cast it to/from int only if you want to perform integer-like operations (e.g., increment) on it.
There are many kind of iterators.
On a vector for example, iterators are usually plain pointers:
template <class T>
class Iterator
{
public:
T* operator->() { return m_pointer; }
private:
T* m_pointer;
};
But this works because a vector is just an array, in fact.
On a doubly-linked list, it would be different, the list would be composed of nodes.
template <class T>
struct Node
{
Node* m_prev;
Node* m_next;
T m_value;
};
template <class T>
class Iterator
{
public:
T* operator->() { return m_node->m_value; }
private:
Node<T>* m_node;
};
Usually, you want you iterator to be as light as possible, because they are passed around by value, so a pointer into the underlying container makes sense.
You might want to add extra debugging capabilities:
possibility to invalidate the iterator
range checking possibility
container checking (ie, checking when comparing 2 iterators that they refer to the same container to begin with)
But those are niceties, and to begin with, this is a bit more complicated.
Note also Boost.Iterator which helps with the boiler-plate code.
EDIT: (update 1 and 2 grouped)
In your case, it's fine if your iterator is just an int, you don't need more. In fact for you strong enum you don't even need an iterator, you just need operator++ and operator-- :)
The point of having a reference to the container is usually to implement those ++ and -- operators. But from your element, just having an int (assuming it's large enough), and a way to get to the previous and next values is sufficient.
It would be easier though, if you had a static vector then you could simply reuse a vector iterator.
An iterator iterates on a specific container. The implementation depends on what kind of container it is. The pointer you return should point to a member of that container. You don't need to copy it, but you do need to keep track of what container you're iterating on, and where you're at (e.g. index for a vector) presumably initialized in the iterator's constructor. Or just use the STL.
What does OfInt return? It appears to be returning the wrong type in this case. It should be returning a T* instead it seems to be returning a T by value which you are then taking the address of. This may produce incorrect behavior since it will loose any update made through ->.
As there is no container I settled on merging iterator into my strong Enum.
I init raw int to -1 to support empty enums (limit == 0) and be able to use regular for loop with TryInc.
Here is the code:
template <uint limit>
class Enum {
public:
static const uint kLimit = limit;
Enum () : raw (-1) {
}
bool TryInc () {
if (raw+1 < kLimit) {
raw += 1;
return true;
}
return false;
}
uint GetRaw() const {
return raw;
}
void SetRaw (uint raw) {
this->raw = raw;
}
static Enum OfRaw (uint raw) {
return Enum (raw);
}
bool operator == (const Enum& other) const {
return this->raw == other.raw;
}
bool operator != (const Enum& other) const {
return this->raw != other.raw;
}
protected:
explicit Enum (uint raw) : raw (raw) {
}
private:
uint raw;
};
The usage:
class Color : public Enum <10> {
public:
static const Color red;
// constructors should be automatically forwarded ...
Color () : Enum<10> () {
}
private:
Color (uint raw) : Enum<10> (raw) {
}
};
const Color Color::red = Color(0);
int main() {
Color red = Color::red;
for (Color c; c.TryInc();) {
std::cout << c.GetRaw() << std::endl;
}
}