473,549 Members | 2,870 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Is it generally safe to inherit from STL iterator classes?

I understand why it is not safe to inherit from STL containers, but I have
found (in SGI STL documentation) that for example bidirectional_i terator
class can be used to create your own iterator classes by inheriting from
it, ie.

class my_bidirectiona l_iterator : public bidirectional_i terator<double>
{
...
};

I'm trying to implement STL compatible iterators for my custom class but I
need to change type returned by dereferencing my iterators, and inheriting
from bidirectional_i terator would make my job much easier of course. Now,
what I'm wondering, do I need to use SGI STL to do that safely, or it is
standard behavior for STL?

I have found few tutorials about creating custom iterators and I think I
understand how to do it, but before I start, I want to know is it worth
(safe) to do it and there is nothing in tutorials that explains that...

T.A.
Sep 23 '06 #1
21 5684
"T.A." <to************ *@gmail.comwrot e:
I understand why it is not safe to inherit from STL containers, but I have
found (in SGI STL documentation) that for example bidirectional_i terator
class can be used to create your own iterator classes by inheriting from
it, ie.

class my_bidirectiona l_iterator : public bidirectional_i terator<double>
{
...
};

I'm trying to implement STL compatible iterators for my custom class but I
need to change type returned by dereferencing my iterators, and inheriting
from bidirectional_i terator would make my job much easier of course. Now,
what I'm wondering, do I need to use SGI STL to do that safely, or it is
standard behavior for STL?
Bidirectional_i terator has no member functions, member variables, or
nested types. It exists solely to simplify the definition of the
functions iterator_catego ry, distance_type, and value_type.

The only reason bidirectional_i terator exists is so you don't have to
put the three typedefs in your class. So inherit away. Do not inherit
from std::vector::it erator though.

--
There are two things that simply cannot be doubted, logic and perception.
Doubt those, and you no longer have anyone to discuss your doubts with,
nor any ability to discuss them.
Sep 23 '06 #2
Daniel T. wrote:
"T.A." <to************ *@gmail.comwrot e:
>I understand why it is not safe to inherit from STL containers, but I
have found (in SGI STL documentation) that for example
bidirectional_ iterator class can be used to create your own iterator
classes by inheriting from it, ie.

class my_bidirectiona l_iterator : public bidirectional_i terator<double>
{
...
};

I'm trying to implement STL compatible iterators for my custom class but
I need to change type returned by dereferencing my iterators, and
inheriting from bidirectional_i terator would make my job much easier of
course. Now, what I'm wondering, do I need to use SGI STL to do that
safely, or it is standard behavior for STL?

Bidirectional_i terator has no member functions, member variables, or
nested types. It exists solely to simplify the definition of the
functions iterator_catego ry, distance_type, and value_type.

The only reason bidirectional_i terator exists is so you don't have to
put the three typedefs in your class. So inherit away. Do not inherit
from std::vector::it erator though.
Huh? I just found myself inheriting from std::set::const _iterator the other
day, and I don't see anything wrong with it. The standard arguments agains
inheriting from non-polymorphic classes do not apply: you don't use
std::vector::it erator* polymorphically and the functions taking
std::vector::it erator& as arguments all should be templated on an iterator
type anyway (and the ones from STL are). Could you please elaborate?

For concreteness, the code where I did it, is in this posting:

http://groups.google.com/group/comp....5246c3ffbb9cfc

It defines a policy tracked<Tto be used as

class TrackedClass : public tracked<Tracked Class{
...
}

and automatically adds to the interface of TrackedClass functionality to
iterate over all objects of type TrackedClass that currently exist.
Underlying this logic is a static std::set< tracked* object since casting
to TrackedClass* is not available in tracked< TrackedClass >. Thus, an
iterator type is provided whose operator* performs the necessary up-cast.
Best

Kai-Uwe Bux
Sep 23 '06 #3
On Sat, 23 Sep 2006 11:12:44 -0400, Kai-Uwe Bux wrote:
Daniel T. wrote:

...

Huh? I just found myself inheriting from std::set::const _iterator the other
day, and I don't see anything wrong with it. The standard arguments agains
inheriting from non-polymorphic classes do not apply: you don't use
std::vector::it erator* polymorphically
OK, this makes a sense... No reason to use iterators polymorphically ...

But I wonder will something like this work nice and safe (from the point of
view of STL algorithms):

class SomeClass;

class MyClass {

private:
typedef SmartPointer<So meClasssmart_po inter;
typedef std::vector<sma rt_pointersmart _pointer_vector ;

smart_pointer_v ector itsContents;

public:
class iterator : public smart_pointer_v ector::iterator {
...
};

iterator begin() { return itsContents.beg in(); }
iterator end() { return itsContents.end (); }
}

Now, when somebody uses, for example, find algorithm on MyClass will it
work as expected, or there are some dangers that I'm not aware of? (I think
it will work but I'm still quite new to C++ so I decided to double check)

TIA
Sep 23 '06 #4
T.A. wrote:
On Sat, 23 Sep 2006 11:12:44 -0400, Kai-Uwe Bux wrote:
>Daniel T. wrote:

...

Huh? I just found myself inheriting from std::set::const _iterator the
other day, and I don't see anything wrong with it. The standard arguments
agains inheriting from non-polymorphic classes do not apply: you don't
use std::vector::it erator* polymorphically

OK, this makes a sense... No reason to use iterators polymorphically ...

But I wonder will something like this work nice and safe (from the point
of view of STL algorithms):

class SomeClass;

class MyClass {

private:
typedef SmartPointer<So meClasssmart_po inter;
typedef std::vector<sma rt_pointersmart _pointer_vector ;

smart_pointer_v ector itsContents;

public:
class iterator : public smart_pointer_v ector::iterator {
...
};

iterator begin() { return itsContents.beg in(); }
iterator end() { return itsContents.end (); }
}

Now, when somebody uses, for example, find algorithm on MyClass will it
work as expected, or there are some dangers that I'm not aware of? (I
think it will work but I'm still quite new to C++ so I decided to double
check)
Thanks for being persistent and sceptical.

So I think I figured out what is wrong about inheriting from standard
iterators: to begin with, it might not even be possible! All iterator types
in the standard container are implementation defined. It follows that,
e.g., std::vector<T>: :iterator might be just a T*. In this case, you simply
cannot inherit from it. Also, there are methods to inhibit inheritance. The
standard has no provisions demanding that std::set<T>::it erator does not
use such techniques to prevent derivation. Thus, whenever you write

class my_iterator : public std::vector<T>: :iterator

you are non-portable because you are relying on a feature of your STL that
happens to allow derivation.

Another problem arises generally from "inheritanc e for convenience":
functions might match. Consider a derivation like

class my_iterator : std::vector<T>: :iterator { ... };

Someone might have defined a function

void do_something ( std::vector<T>: :iterator from,
std::vector<T>: :iterator to ) { ... }

Note that my_iterator is a std::vector<T>: :iterator. Thus, you can call
do_something on your container. The bad thing, however, is that the
parameters will be sliced and the semantics of the vector iterators will be
used. Very likely this will give rise to a surprising bug. Arguably, the
designer of do_something() is at least as guilty as the designer of
my_iterator: had do_something() been properly templated, there would be no
problem.

So, what about algorithms from the standard library? They are all properly
templated, so we should be fine, right? Well, there still is a catch:
consider Mr. I-type-everything-in-one-line. He writes:

my_iterator a_iter;
my_iterator b_iter;
...
std::transform( a_iter++, b_iter--, ... );

What happend? We inherited from std::vector<T>: :iterator so that we do not
have to write all those member functions ourselves, right? Well, too bad:
the postfix operator ++ returns a std::vector<T>: :iterator and not a
my_iterator. Thus, the wrong template will be chosen.
I guess, I thoroughly refuted my initial thought that there is nothing wrong
with inheriting from std::...<T>::it erator. It is, indeed, riddled with
difficulties. Oh well, I better revise the tracked<Ttempla te to use
composition instead of derivation.
Sorry for the confusion

Kai-Uwe Bux
Sep 24 '06 #5
On Sat, 23 Sep 2006 21:18:35 -0400, Kai-Uwe Bux wrote:
On Sat, 23 Sep 2006 11:12:44 -0400, Kai-Uwe Bux wrote:

Thanks for being persistent and sceptical.

So I think I figured out what is wrong about inheriting from standard
iterators: to begin with, it might not even be possible! All iterator types
in the standard container are implementation defined. It follows that,
e.g., std::vector<T>: :iterator might be just a T*. In this case, you simply
cannot inherit from it. Also, there are methods to inhibit inheritance. The
standard has no provisions demanding that std::set<T>::it erator does not
use such techniques to prevent derivation. Thus, whenever you write

class my_iterator : public std::vector<T>: :iterator

you are non-portable because you are relying on a feature of your STL that
happens to allow derivation.

Another problem arises generally from "inheritanc e for convenience":
functions might match. Consider a derivation like

class my_iterator : std::vector<T>: :iterator { ... };

Someone might have defined a function

void do_something ( std::vector<T>: :iterator from,
std::vector<T>: :iterator to ) { ... }

Note that my_iterator is a std::vector<T>: :iterator. Thus, you can call
do_something on your container. The bad thing, however, is that the
parameters will be sliced and the semantics of the vector iterators will be
used. Very likely this will give rise to a surprising bug. Arguably, the
designer of do_something() is at least as guilty as the designer of
my_iterator: had do_something() been properly templated, there would be no
problem.

So, what about algorithms from the standard library? They are all properly
templated, so we should be fine, right? Well, there still is a catch:
consider Mr. I-type-everything-in-one-line. He writes:

my_iterator a_iter;
my_iterator b_iter;
...
std::transform( a_iter++, b_iter--, ... );

What happend? We inherited from std::vector<T>: :iterator so that we do not
have to write all those member functions ourselves, right? Well, too bad:
the postfix operator ++ returns a std::vector<T>: :iterator and not a
my_iterator. Thus, the wrong template will be chosen.

I guess, I thoroughly refuted my initial thought that there is nothing wrong
with inheriting from std::...<T>::it erator. It is, indeed, riddled with
difficulties. Oh well, I better revise the tracked<Ttempla te to use
composition instead of derivation.

Sorry for the confusion

Kai-Uwe Bux
So I guess it is true that only thing to inherit from safely are base
iterator classes (in this case probably the best one would be
std::random_acc ess_iterator) and reimplemetation of whole my_iterator
interface. OK, I probably can do that... Now one more thing... I have found
this in docs:

"random_access_ iterator is an iterator base class: it is intended that an
iterator that is a model of Random Access Iterator, and whose value type
and distance type are T and Distance, may be defined by inheriting from
random_access_i terator<T, Distance>
....
This class is no longer part of the C++ standard, although it was present
in early drafts of the standard. It is retained in this implementation for
backward compatibility."

As you see, even this is obsolete... As I understand, using iterator_traits
mechanism is currently the way to implement custom iterator types in
standard way:

"If you are defining a new iterator type I, then you must ensure that
iterator_traits <Iis defined properly. There are two ways to do this.
First, you can define your iterator so that it has nested types
I::value_type, I::difference_t ype, and so on. Second, you can explicitly
specialize iterator_traits for your type. The first way is almost always
more convenient, however, especially since you can easily ensure that your
iterator has the appropriate nested types just by inheriting from one of
the base classes input_iterator, output_iterator , forward_iterato r,
bidirectional_i terator, or random_access_i terator.

Note that iterator_traits is new; it was added to the draft C++ standard
relatively recently. Both the old iterator tags mechanism and the new
iterator_traits mechanism are currently supported [1], but the old iterator
tag functions are no longer part of the standard C++ library and they will
eventually be removed. "

And no inheritance is involved in that. A bit more work than simply
inheriting from existing iterators, though, but that's the way to do it...
Thanks for your help...

Cheers.
Sep 24 '06 #6
Kai-Uwe Bux <jk********@gmx .netwrote:
Daniel T. wrote:
>"T.A." <to************ *@gmail.comwrot e:
>>I understand why it is not safe to inherit from STL containers,
but I have found (in SGI STL documentation) that for example
bidirectional _iterator class can be used to create your own
iterator classes by inheriting from it, ie.

class my_bidirectiona l_iterator : public
bidirectional _iterator<doubl e{ ... };

I'm trying to implement STL compatible iterators for my custom
class but I need to change type returned by dereferencing my
iterators, and inheriting from bidirectional_i terator would make
my job much easier of course. Now, what I'm wondering, do I need
to use SGI STL to do that safely, or it is standard behavior for
STL?

Bidirectional_ iterator has no member functions, member variables,
or nested types. It exists solely to simplify the definition of the
functions iterator_catego ry, distance_type, and value_type.

The only reason bidirectional_i terator exists is so you don't have
to put the three typedefs in your class. So inherit away. Do not
inherit from std::vector::it erator though.

Huh? I just found myself inheriting from std::set::const _iterator
the other day, and I don't see anything wrong with it. The standard
arguments agains inheriting from non-polymorphic classes do not
apply: you don't use std::vector::it erator* polymorphically and the
functions taking std::vector::it erator& as arguments all should be
templated on an iterator type anyway (and the ones from STL are).
Could you please elaborate?
You shouldn't do it for the same reasons you shouldn't derive from
std::string or std::vector. There are always exceptions of course and
maybe yours applies but the general rational is this:

There are no protected members in std::set::const _iterator that you need
access to, there is (should be) no context where a function takes a
std::set::const _iterator* as a parameter and you need to wrap the
const_iterator to intercept calls to it, and there are no virtual
member-functions in std::set::const _iterator for you to override.
Therefore, there is no reason to derive from std::set::const _iterator.

The stuff you put in the derived class will likely work with any const
iterator that has the same semantics as std::set::const _iterator, and
you are creating an artificial limitation by deriving from
std::set::const _iterator.

--
There are two things that simply cannot be doubted, logic and perception.
Doubt those, and you no longer have anyone to discuss your doubts with,
nor any ability to discuss them.
Sep 24 '06 #7
"T.A." <to************ *@gmail.comwrot e:
So I guess it is true that only thing to inherit from safely are base
iterator classes (in this case probably the best one would be
std::random_acc ess_iterator) and reimplemetation of whole my_iterator
interface.
Maybe an example will help:

/*
* dat_fibonacci.h
*
* Created by Daniel on 1/30/06.
* Copyright 2006 Daniel Tartaglia. All rights reserved.
*
*/

#pragma once

#include <iterator>

namespace dat {

class fibonacci: public std::iterator< std::forward_it erator_tag, int >
{
int prev_value, value, max;
public:
fibonacci(): prev_value(0), value(0), max(0) { }
explicit fibonacci(int m): prev_value(0), value(1), max(m) { }
const int operator*() const { return value; }
fibonacci& operator++() {
int tmp = value;
value += prev_value;
prev_value = tmp;
return *this;
}
fibonacci operator++(int) {
fibonacci tmp(*this);
++(*this);
return tmp;
}
friend bool operator==(cons t fibonacci& lhs, const fibonacci& rhs) {
bool result = false;
if ( lhs.value == 0 && rhs.value == 0 ) result = true;
else if ( rhs.value == 0 && !( lhs.value < lhs.max ) )
result = true;
else if ( lhs.value == 0 && !( rhs.value < rhs.max ) )
result = true;
else if ( lhs.prev_value == rhs.prev_value &&
lhs.value == rhs.value && lhs.max == rhs.max )
result = true;
return result;
}
};

bool operator!=(cons t fibonacci& lhs, const fibonacci& rhs) {
return !(lhs == rhs);
}

}

--
There are two things that simply cannot be doubted, logic and perception.
Doubt those, and you no longer have anyone to discuss your doubts with,
nor any ability to discuss them.
Sep 24 '06 #8
Daniel T. wrote:
>
There are no protected members in std::set::const _iterator that you need
access to, there is (should be) no context where a function takes a
std::set::const _iterator* as a parameter and you need to wrap the
const_iterator to intercept calls to it, and there are no virtual
member-functions in std::set::const _iterator for you to override.
Therefore, there is no reason to derive from std::set::const _iterator.
There is a very good reason for deriving from std::set::const _iterator:
when you do, you don't need to reimplement the member functions that it
provides. Except, of course, for the ones where you want different behavior.
The stuff you put in the derived class will likely work with any const
iterator that has the same semantics as std::set::const _iterator, and
you are creating an artificial limitation by deriving from
std::set::const _iterator.
Maybe, but that sounds like overdesign. If the current application works
with set instances and needs modified iterators, then deriving from
set::const_iter ator is perfectly appropriate. If some future application
needs something similar but more general, that's the time to add the
generality.

--

-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
Sep 24 '06 #9
Pete Becker wrote:
Daniel T. wrote:

There are no protected members in std::set::const _iterator that you need
access to, there is (should be) no context where a function takes a
std::set::const _iterator* as a parameter and you need to wrap the
const_iterator to intercept calls to it, and there are no virtual
member-functions in std::set::const _iterator for you to override.
Therefore, there is no reason to derive from std::set::const _iterator.

There is a very good reason for deriving from std::set::const _iterator:
when you do, you don't need to reimplement the member functions that it
provides. Except, of course, for the ones where you want different behavior.
Except for the fact that there are no member functions that a
std::set::const _iterator type is required to provide. The Standard
requires only that the const_iterator type support certain operations -
there is no requirement concerning how those operations are to be
implemented or even any requirement that the library must implement
them itself. A built-in type that supported the necessary built-in
operations with built-in operators would qualify as well. So any class
derived from set's const_iterator cannot be sure of the interface it
will actually be inheriting, nor can it be sure that inheritance is
even an option: after all, set's const_iterator may be a typedef for a
built-in type, such as a pointer.

The stuff you put in the derived class will likely work with any const
iterator that has the same semantics as std::set::const _iterator, and
you are creating an artificial limitation by deriving from
std::set::const _iterator.

Maybe, but that sounds like overdesign. If the current application works
with set instances and needs modified iterators, then deriving from
set::const_iter ator is perfectly appropriate. If some future application
needs something similar but more general, that's the time to add the
generality.
The sensible design is to wrap the iterator in a template class, and
implement the handful of operations the program actually will use as
class methods that (in the default case) simply perform the same,
corresponding operation on the wrapped iterator instance.

Any design that involves deriving from std::set::const _iterator is
necessarily a non-portable and fragile implementation based entirely on
the inner workings of a particular implementation of std::set written
by someone else. In other words, there is no solid foundation. Future
revisions of the same Standard library (or even debug or non-debug
builds of the same library) could well render the design's current
assumptions false. Worse, there is no assurance that a design broken in
this way would be reported as an error. Instead the program may still
compile, but when run, would fail silently.

Greg

Sep 24 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
4363
by: greg | last post by:
Hello all, I havent used STL containers much, as I am used to MFC containers/classes always ..The differences that I could see is iterators and algorithms. The algorithms providing some basic functinaloties which are also present in respective MFc container classes, I wanted to know what is the main powers in Iterators ?? I have written...
2
2838
by: Rex_chaos | last post by:
Hi all, I am writing my own container and need an iterator. I am hesitating if I should my iterator should inherited from std::iterator or just write my own one. Please give me an idea. BTW, if I write my own one, should I let it defined inside my container(inner class) or just be a complelely independent class. Thanks.
8
2191
by: Generic Usenet Account | last post by:
To settle the dispute regarding what happens when an "erase" method is invoked on an STL container (i.e. whether the element is merely removed from the container or whether it also gets deleted in the process), I looked up the STL code. Erase certainly does not delete the memory associated with the element. However, it appears that the...
5
2581
by: Ernst Murnleitner | last post by:
Hello, is it possible to derive from std::vector and derive also its iterator? If I do it like in the example below, I get a problem when I need the begin of the vector: begin() returns the derived iterator. I need the derived iterator in order to overload the operator++. But I want to use also std::vector<PBaseItem>::begin() in order...
4
4452
by: lwickland | last post by:
Non-visual C# objects on a webpage are not marked as "safe for scripting" I'm developing .NET components in C# which are used as ActiveX-style controls on web pages that are displayed inside a custom browser which is based on the IE web browser control. On 3 of about 100 PCs that the controls have been tried on, the browser produces the...
2
2002
by: Lorenzo Castelli | last post by:
This is an old problem of mine. Basically I have an abstract base class which represents a generic iterator over a collection of elements, and various derived classes that implement the traversing on specific data structures. For each iterator I want to be able to specify the four possible const combinations, corresponding to the various ...
2
2678
by: Christoph Heindl | last post by:
Hi, I'm currently struggling with a design decision. One of my classes (named Attributable) has a protected member of type std::list<StrongReference<Attribute> > Basically the list has strong references that point to Attribute's. In Attributable i want to provide an stl like interface for bidirectional iterators like:
1
6227
by: David Bilsby | last post by:
All Apologies for cross posing this but I am not sure if this is a VC 8 STL bug or simply an invalid use of the iterator. I have a PCI card access class which basically abstracts a third party library from the higher level classes. This low level class is used to allocate locked pages of memory before doing a DMA. The third party library...
3
3064
by: andreas.zetterstrom | last post by:
I'm implementing some different c++ classes which I want to be thread safe. All these classes contain lists or arrays of some kind. I'm using protected sections to make them thread safe. The question then is: how do you in a nice safe way pick values out of the list? The easiest way is to have a pair of Lock, Unlock functions, but this also...
0
7551
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7477
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7991
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
1
7509
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
6084
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5396
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
3503
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
1084
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
790
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.