const and pointers - c++

Edit1: I realize this is hard to understand this question without having an insight of what I'm trying to do. The class A is not complete but it essentially stand for a C-array "proxy" (or "viewer" or "sampler"). One interesting usage is too present a C-array as a 2d grid (the relevant function are not shown here). The property of this class are the following:
it should not own the data - no deep copyy
it should be copyable/assignable
it should be lightweight (
it should preserve constness (I'm having trouble with this one)
Please do not question the purpose or the design: they are the hypothesis of the question.
First some code:
class A
{
private:
float* m_pt;
public:
A(float* pt)
:m_pt(pt)
{}
const float* get() const
{
return m_pt;
}
void set(float pt)
{
*m_pt = pt;
}
};
void gfi()
{
float value = 1.0f;
const A ac(&value);
std::cout<<(*ac.get())<<std::endl;
A a = ac;
a.set(2.0f);
std::cout<<(*ac.get())<<std::endl;
}
Calling "gfi" generate the following output:
1
2
Assigning a with ac is a cheap way to shortcut the constness of ac.
Is there a better way to protect the value which m_pt point at?
Note that I DO want my class to be copyable/assignable, I just don't want it to loose its constness in the process.
Edit0: I also DO want to have a pointer in there, and no deep copy please (let say the pointer can be a gigantic array).
Edit2: thanks to the answers, I came to the conclusion that a "const constructor" would be a useful thing to have (at least in this context). I looked it up and of course I'm not the same one who reached this conclusion. Here's an interesting discussion:
http://www.rhinocerus.net/forum/language-c-moderated/569757-const-constructor.html
Edit3: Finally got something which I'm happy with. Thanks for your help. Further feedback is more than welcome
template<typename T>
class proxy
{
public:
typedef T elem_t;
typedef typename boost::remove_const<T>::type elem_unconst_t;
typedef typename boost::add_const<T>::type elem_const_t;
public:
elem_t* m_data;
public:
proxy(elem_t* data = 0)
:m_data(data)
{}
operator proxy<elem_const_t>()
{
return proxy<elem_const_t>(m_data);
}
}; // end of class proxy
void test()
{
int i = 3;
proxy<int> a(&i);
proxy<int> b(&i);
proxy<const int> ac(&i);
proxy<const int> bc(&i);
proxy<const int> cc = a;
a=b;
ac=bc;
ac=a;
//a=ac; // error C2679: binary '=' : no operator found which takes a right-hand operand of type...
//ac.m_data[0]=2; // error C3892: 'ac' : you cannot assign to a variable that is const
a.m_data[0]=2;
}

Your class is badly designed:
it should use float values, not pointers
if you want to use pointers, you probably need to allocate them dynamically
and then you need to give your class a copy constructor and assignment operator (and a destructor) , which will solve the problem
Alternatively, you should prevent copying and assignment by making the copy constructor and assignment op private and then not implementing them.

You can trick around with proxy pattern and additional run-time constness boolean member. But first, please tell us why.

Effectively your class is like an iterator that can only see one value. It does not encapsulate your data just points to it.
The problem you are facing has been solved for iterators you should read some documentation on creating your own iterator and const_iterator pairs to see how to do this.
Note: in general a const iterator is an iterator that cannot be incremented/decremented but can change the value it points to. Where as a const_iterator is a different class that can be incremented/decremented but the value it points to cannot be changed.
This is the same as the difference between const float * and float *const. In your case A is the same as float * and const A is the same as float *const.
To me your choices seem to be:
Encapsulate your data.
Create a separate const_A class like iterators do
Create your own copy constructor that does not allow copies of const A eg with a signature of A(A & a);

EDIT: considering this question some more, I think you are misinterpreting the effect of const-correctness on member pointers. Consider the following surprising example:
//--------------------------------------------------------------------------------
class CNotSoConstPointer
{
float *mp_value;
public:
CNotSoConstPointer(float *ip_value) : mp_value(ip_value) {}
void ModifyWithConst(float i_value) const
{
mp_value[0] = i_value;
}
float GetValue() const
{
return mp_value[0];
}
};
//--------------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
float value = 12;
const CNotSoConstPointer b(&value);
std::cout << b.GetValue() << std::endl;
b.ModifyWithConst(15);
std::cout << b.GetValue() << std::endl;
while(!_kbhit()) {}
return 0;
}
This will output 12 and then 15, without ever being "clever" about the const-correctness of the const not-so-const object. The reason is that only the pointer ITSELF is const, not the memory it points to.
If the latter is what you want, you'll need a lot more wrapping to get the behavior you want, like in my original suggestion below or Iain suggestion.
ORIGINAL ANSWER:
You could create a template for your array-proxy, specialized on const-arrays for the const version. The specialized version would have a const *m_pt, return a const pointer, throw an error when you try to set, and so on.
Edit: Something like this:
template<typename T>
class TProxy
{
T m_value;
public:
TProxy(T i_t) : m_value(i_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.m_value) {}
T get() { return m_value; }
void set(T i_t) { m_value = i_t; }
};
template<typename T>
class TProxy<const T *>
{
const T *mp_value;
public:
TProxy(const T *ip_t) : mp_value(ip_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.mp_value) {}
T get() { return m_value; }
};

Why not replace float* with float in A. If you don't either the original owner of the float that the float* references can change it, or anyone prepared to do a mutable cast on the return value from a::get.

const is always just a hint to the compiler; there are no ways to make a variable permanently read-only.

I think you should use deep copy and define your own assingment operator and copy constructor.
Also to return handle to internal data structure in not a good practice.

You can deny the copy-constructor for certain combinations of arguments:
For instance, adding the constructor;
A(A& a) :m_pt(a.m_pt) { m_pt = a.m_pt; }
prevents any instance of A being initialised with a const A.
This also prevents const A a2 = a1 where a1 is const, but you should never need to do this anyway, since you can just use a1 directly - it's const even if you could make a copy, a2 would be forever identical to a1.

Related

Removing constness from reference returned by const accessor method versus adding a non-const accessor method

Let's consider the following code:
Class MyVeryAccessibleClass
{
public:
const std::vector<int>& getVect() const {return vect_m;};
private:
std::vector<int> vect_m;
};
Class MyInitClass
{
MyInitClass() : importantInt_m{10}{};
void init();
protected:
int importantInt_m;
};
My project is built in a way that it has to be MyInitClass::init() that initializes or modifies MyVeryAccessibleClass::vect_m.
Some other classes will also have access to MyVeryAccessibleClass::vect_m but I don't want them to be able to modify it, they should only be able to read it.
I thought of 2 solutions:
Casting away the constness of getVect() in init (and only there). This is the solution I am leaning towards, but I've read that const_cast should be avoided so I am not sure this is correct:
MyInitClass::init()
{
MyVeryAccessibleClass* class_l = methodToGetMyVeryAccessibleClassInOneWayOrAnother();
auto vect_l& = const_cast<std::vector<int>&> (class_l ->getVect());
vect_l.push_back(importantInt_m);
}
Adding a non-const accessor to MyVeryAccessibleClass. I don't really like this solution because it means that if in another part of the code I use a pointer to MyVeryAccessibleClass, it will call the non-const accessor, and this accessor should only ever be used in MyInitClass::init()
Class MyClass
{
public:
const std::vector<int>& getVect() const {return vect_m;};
// I've read that I could also call the const accessor from here, but that is not really the point
std::vector<int>& getVect() {return vect_m;};
private:
std::vector<int> vect_m;
};
MyInitClass::init()
{
MyVeryAccessibleClass* class_l = methodToGetMyVeryAccessibleClassInOneWayOrAnother();
auto vect_l& = class_l ->getVect();
vect_l.push_back(importantInt_m);
}
MyOtherClass::doStuff()
{
MyVeryAccessibleClass* class_l = methodToGetMyVeryAccessibleClassInOneWayOrAnother();
// I don't want that.
// I guess one could precise const auto vect_l& to call the const accessor or use the new std::as_const
// But not everybody is familiar with that and I felt like I should not even allow the possibility of making a mistake
auto vect_l& = class_l->getVect();
// Mistake far less obvious than this one but that modifies the vector:
vect_l.push_back(15);
}
Is there a better solution that I didn't think of ? And if not, should I go with solution 1 or solution 2 ? My sentiment was that since I only ever want to modify MyVeryAccessibleClass::vect_m in MyInitClass::init, it was OK to do a const_cast there and not have a non-const accessor in MyVeryAccessibleClass.
You can declare your class MyInitClass as a friend of MyVeryAccessibleClass.
Let's see the code in action.
class MyVeryAccessibleClass
{
friend class MyInitClass;
private:
const std::vector<int> vect_m;
}
Now Let's look at the MyInitClass constructor.
MyInitClass::init()
{
MyVeryAccessibleClass* class_l = methodToGetMyVeryAccessibleClassInOneWayOrAnother();
auto vect_l& = class_l->vect_l;
vect_l.push_back(importantInt_m);
}

Const correctness in struct initialization

I'm playing with C++ and const-correctness right now.
Assume you have the following structure
template <typename T>
struct important_structure {
public:
T* data;
int a;
important_structure(const T& el, int a);
void change();
};
template <typename T>
void important_structure<T>::change() {
//alter data field in some way
}
template <typename T>
important_structure <T>::important_structure(const T& el, int a) : data(&el), a(a) //error line {
};
int main() {
important_structure<int>* s = new important_structure<int>{5, 3};
}
When compiling with std=c++11, the compiler returns the following error:
invalid conversion from ‘const int*’ to ‘int*’
Now, I know it's unsafe to cast a const int* to int*. The problem is that I have a data structure and I don't want to put the field data as a constant.
However, I don't want to remove the const qualifier in the constructor since, I think, it's informative for future developers: it clearly says that el won't be modified by the function. Still the field data may be modified by some other function in important_structure.
My question is: How can I deal with fields which are initialized in the costructor and altered in some other function?
Most of const correctness deals with simple answers, but no question (I think) deals with scenarios where a const parameter is passed to a data structure and then such data structure is altered by someone else.
Thanks for any kind reply
passing el as a const reference doesn't just mean the function will not change el during the run of the function, it means because of this function call, el won't be changed at all. And by putting the address of el into non-const data, you violate that promise.
So, the clean solution, if you indeed want to change data, is removing the const. since it is not informative to future developers, but misleading. Casting away the const would be very bad here.
Let's use a simple class as T type of important_struct:
class Data
{
public:
Data() : something(0){}
Data(int i) : something(i){}
Data(const Data & d) : something(d.something){}
//non-const method: something can be modified
void changeSomething(int s){ something += s; }
//const method: something is read-only
int readSomething() const { return something; }
private:
int something;
};
This class has a very simple, yet well encapsulated, status, i.e. the int something field, which is accessed through methods in a very controlled way.
Let (a simplified version of) important_structure hold an instance of Data as a private field:
template <typename T>
struct important_structure
{
public:
important_structure(T * el);
void change();
int read() const;
private:
T* data;
};
We can assign a Data instance to an important_structure instance this way:
important_structure<Data> s(new Data());
The instance is assigned in construction:
template <typename T>
important_structure <T>::important_structure(T * el) : data(el) {}
Now the great question: do important_structure take ownership of the Data instances it holds? The answer must be made clear in documentation.
If it is yes, important_structure must take care of memory cleanup, e.g. a destructor like this one is required:
template<typename T>
important_structure<T>::~important_structure()
{
delete data;
}
Notice that, in this case:
Data * p = new Data()
// ...
important_structure<Data> s(p);
//p is left around ...
another pointer to the Data istance is left around. What if someone mistakenly call delete on it? Or, even worse:
Data d;
// ...
important_structure<Data> s(&p); //ouch
A much better design would let important_structure own its own Data instance :
template <typename T>
struct important_structure
{
public:
important_structure();
void change();
// etc ...
private:
T data; //the instance
};
but this is maybe simplistic or just unwanted.
One could let important_structure copy the instance it will own:
template<typename T>
important_structure<T>::important_structure(const T &el)
{
data = el;
}
the latter being the constructor provided in the question: the object passed won't be touched, but copied. Obviously, there are two identical Data objects around, now. Again, the result could not be what we needed in the first place.
There is a third way, in the middle: the object is instantiated outside the owner, and moved to it, using move semantics.
As an example, let's give Data a move assignment operator:
Data & operator=(Data && d)
{
this->something = d.something;
d.something = 0;
return *this;
}
and let important_structure provide a constructor which accepts an rvalue reference of T:
important_structure(T && el)
{
data = std::move(el);
}
One can still pass a Data instance using a temporary as the required rvalue:
important_structure<Data> s(Data(42));
or an existing one, providing the required reference from an lvalue, thanks to std::move:
Data d(42);
// ...
important_structure<Data> x(std::move(d));
std::cout << "X: " << x.read() << std::endl;
std::cout << "D: " << d.readSomething() << std::endl;
In this second example, the copy held by important_structure is considered the good one while the other is left in a valid but unspecified state, just to follow the standard library habits.
This pattern is, IMHO, more clearly stated right in code, expecially if considered that this code will not compile:
Data d(42);
important_structure<Data> x (d);
Whoever wants an instance of important_structure must provide a temporary Data instance or explicitly move an existing one with std::move.
Now, let the important_structure class be a container, as you asked in comment, so that data is somehow accessible from outside. Let's give a method like this to the important_structure class:
const T & owneddata() { return data; }
Now, we can use data const methods like this:
important_structure<Data> s(Data(42));
std::cout << s.owneddata().readSomething() << std::endl;
but calls to `Data' non-const methods will not compile:
s.owneddata().changeSomething(1000); //not compiling ...
If in need of it (hope not), expose a non-const reference:
T & writablereference() { return data; }
Now the data field is at full disposal:
s.writablereference().changeSomething(1000); //non-const method called
std::cout << s.owneddata().readSomething() << std::endl;
Using const T& el and data(&el) is a really bad idea, because it implies that you could write:
new important_structure<int>{5, 3};
But to write new important_structure<int>{5, 3}; would result in data holding an address that would no longer be valid immediately after calling the constructor.
If you want that the point data can be changed, but that the value where the pointer points to cannot be changed, then you want to write it that way:
template <typename T>
struct important_structure {
public:
T const * data;
int a;
important_structure(T const * el, int a);
void change();
};
template <typename T>
void important_structure<T>::change() {
//alter data field in some way
}
template <typename T>
important_structure <T>::important_structure( T const * el, int a) : data(el), a(a) { //error line
};
int main() {
int i = 5;
important_structure<int>* s = new important_structure<int>{&i, 3};
}

shared_ptr<T> to shared_ptr<T const> and vector<T> to vector<T const>

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.

Const and non-const access resolves to different overloads?

Let me say we have a simple programming task. But for the sake of clarity I start with few code samples.
First of all we written a some kind of data container class but for the purposes of task no matter what the class is. We just need it to behave const-correct.
class DataComponent {
public:
const std::string& getCaption() const {
return caption;
}
void setCaption(const std::string& s) {
caption = s;
}
private:
std::string caption;
};
Then let us assume we've got a generic class that behaves like facade over arbitrary incapsulated class instance. Say we overloaded member access operator (->).
template <typename T> class Component {
public:
Component() { instance = new T(); }
...
const T* operator-> () const {
return instance;
}
T* operator-> () {
// but there might be additional magic
return instance;
}
private:
T *instance;
};
At this point I should say how I want this to work:
if we're calling non-const member functions of underlying class through member access operator (component->setCaption("foo")) compilier treats non-const T* operator-> () as the best choice.
otherwise if we are trying to call const member functions of underlying class same way (component->getCaption()) compiliers selects const T* operator-> () const on the other hand.
This code sample above won't work this way so I'm curious about possibility to give compiler a behavior like that I have mentioned. Any propositions.
EDIT: Let our member access operator overloaded this way:
const T* operator-> () const { return instance; }
T* operator-> () {
cout << "something going change" << endl;
return instance;
}
And let us have a variable Component<DataComponent> c somewhere. Then on the call to c->getCaption() stdout should remain silent but on the call to c->setCaption("foo") stdout should warn us that something is going to change. VS 2010 compilier makes stdout warn us on each of these calls.
I understand that such semantics suppose that c behaves as const and non-const at the same time. But curiousity is still in my mind.
Whether a const or non-const member is invoked is determined purely by the constness of the object on which it is invoked, not by some subsequent operation. That determination is made before any consideration of the particular method you're invoking in DataComponent. You could still hack up the required functionality less directly using proxy object around DataComponent, with both const and non-const forwarding getCaption()s.
EDIT: details as requested (off the top of my head). You'll need to forward declare some of this stuff - I didn't bother as it makes it even more confusing. Do chip in with any concerns / feedback. Note that this basically assumes you can't / don't want to modify Component for some reason, but it's not a generic templated solution that can simply be wrapped around any arbitrary type - it's very heavily coupled and has a high maintenance burden.
// know they can't call a non-const operation on T, so this is ok...
const T* Component::operator->() const { return instance; }
// they might invoke a non-const operation on T, so...
DataComponent::Proxy Component::operator->() { return DataComponent.getProxy(*this); }
in class DataComponent:
struct Proxy
{
Component& c_;
DataComponent& d_;
Proxy(Component& c, DataComponent& d) : c_(c), d_(d) { }
const std::string& get_caption() const { return d_.get_caption(); }
void set_caption(const std::string& s)
{
c_.on_pre_mutator(d_);
d_.set_caption(s);
c_.on_post_mutator(d_);
}
};
then
DataComponent::Proxy DataComponent::getProxy(Component& c) { return Proxy(c, *this); }
So, this means somewhere you have to hand-code forwarding functions. It's a pain, but if you're doing this for debugging or testing it's not unreasonable. If you're doing this so you can add a lock or something, then there are probably better alternatives.

How to create operator-> in iterator without a container?

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