Using iterator to retrieve const values pointed to in containers - c++

Const casting container value-types seems not possible. A comment in the other question suggests iterators as a solution, yet does not go into detail.
Since I seemingly cannot simply convert a container from a non-const to a const version as a function parameter, I arrive at Iterators to maybe be able to do the job.
I actually have a vector<shared_ptr<Thing> > to be treated as const vector<shared_ptr<Thing const> >.
With it I intend to use the shared_ptr<Thing const> as further references in other structures, without allowing those structures to alter the Things. Those structures may create their own objects, stored by their own shared_ptr, if they want slightly different content within their containers, while still actively sharing most Things with other objects.
So I would need either shared_ptr<const Thing>&, or const shared_ptr<const Thing>& from an Iterator through the sequence. Either would suffice, but just because one can be indifferent about passing references in this example, because of shared_ptr's copy semantics are about just that.
Yet even just using default const_iterator, retrieved by cbegin(),c.end() and such, will give me a const shared_ptr<Thing>& instead.
Edit: To copy the vector element for element would be one way technically, as in the other question, yet undesired for interface reasons. I am going for reinterpretation here, not copy.
Any suggestions on where a workaround might lie?

Based on your situation, it sounds like defining a custom iterator with the semantics you want is the safe and simple way to go. It's technically correct, hard to accidentally misuse, and fairly fast, just requiring a shared_ptr copy on iterator dereference.
I always recommend boost::iterator_facade or boost::iterator_adaptor for creating an iterator type. Since it will contain the original vector iterator as a "base" implementation, iterator_adaptor is helpful.
class const_Thing_ptr_iterator :
public boost::iterator_adaptor<
const_Thing_ptr_iterator, // CRTP derived type
std::vector<std::shared_ptr<Thing>>::const_iterator, // base iterator type
std::shared_ptr<const Thing>, // value_type
std::random_access_iterator_tag, // traversal type
std::shared_ptr<const Thing> // reference
>
{
public:
const_Thing_ptr_iterator() = default;
explicit const_Thing_ptr_iterator(base_type iter)
: iterator_adaptor(iter) {}
};
The reference iterator type would be std::shared_ptr<const Thing>& by default, but in this case it can't be a reference since there is no object of that type. Normally the class would define some of the behavior functions like dereference or increment, but none are needed here: the only change from the base vector iterator is to the return type of operator*, and the default reference dereference() const { return *base_reference(); } works fine by implicit conversion from const std::shared_ptr<Thing>& to std::shared_ptr<const Thing>.
The class could also be a template taking Thing as its type parameter, to create multiple iterator types.
Then to provide a container-like view object, we can use C++20's std::ranges::subrange to provide begin() and end() and a few other things helping the out the range templates:
#include <ranges>
class const_Thing_ptrs_view
: public std::ranges::subrange<const_Thing_ptr_iterator>
{
public:
explicit const_Thing_ptrs_view(const std::vector<std::shared_ptr<Thing>> &vec)
: subrange(const_Thing_ptr_iterator(vec.begin()),
const_Thing_ptr_iterator(vec.end())) {}
};
Or if that's not available, a simple class with begin() and end():
class const_Thing_ptrs_view {
public:
explicit const_Thing_ptrs_view(const std::vector<std::shared_ptr<Thing>> &vec)
: m_begin(vec.begin()), m_end(vec.end()) {}
const_Thing_ptr_iterator begin() const { return m_begin; }
const_Thing_ptr_iterator end() const { return m_end; }
private:
const_Thing_ptr_iterator m_begin;
const_Thing_ptr_iterator m_end;
};
Demo on godbolt. (Clang doesn't like the ranges code due to this libstdc++ incompatibility; I'm not sure how to get godbolt to switch it to clang's libc++.)

A pretty simple approach might be maintaining a vector of pointers to const already internally – and casting the const away on internal usage.
Warning: Don't consider this as an invitation for doing so carelessly! If you do so, at some point of time you will break something. After all those objects are const for a reason!
In given case, though, this reason is a pure external one – if it wasn't for the public interface the objects wouldn't ever have got const anyway so casting it away again is valid in this very specific case.
class DataOwner
{
public:
std::vector<std::shared_ptr<Thing const>> const& data() const
{
return m_data;
}
void modify()
{
m_data.emplace_back(new Thing());
at(0)->doSomething();
}
// for convenience of the user you might optionally duplicate
// the const interface of `std::vector` here as well
private:
std::vector<std::shared_ptr<Thing const>> m_data;
Thing* at(size_t index)
{
// only one single location where const-casting
// remember: generally a dangerous operation,
// here one of the view valid use cases
return const_cast<Thing*>(m_data[index].get());
// don't forget to document in your own code WHY it is valid here
}
};

Copying around all the shared pointers into new vectors can become pretty expensive quickly, especially if the original source vector gets updated frequently and referring instances thus need to fetch updates again and again.
I personally would thus rather provide either a wrapper around std::vector or around std::shared_ptr that give modifying access only to the data owner (who would be a friend then) while the general interface only allows non-modifying access. Wrapping the vector, though, will require the shared pointers to get copied whenever retrieving one, thus involving reference counting, additionally the solution gets more complex, thus going with the wrapper around the shared pointer here:
struct Thing
{
void doSomething() { }
void doSomethingElse() const { }
};
class DataOwner
{
public:
class SharedPointer
{
public:
SharedPointer(SharedPointer const&) = default;
SharedPointer(SharedPointer&&) = default;
SharedPointer& operator=(SharedPointer const&) = default;
SharedPointer& operator=(SharedPointer&&) = default;
Thing const& operator*() const
{
return *m_data;
}
Thing const* operator->() const
{
return m_data.get();
}
Thing const* get() const
{
return m_data.get();
}
// should be all of the public interface needed...
private:
friend class DataOwner;
SharedPointer(Thing* t) : m_data(t) { }
std::shared_ptr<Thing> m_data;
};
std::vector<SharedPointer> const& data() const
{
return m_data;
}
void modify()
{
m_data.emplace_back(SharedPointer(new Thing()));
m_data[0].m_data->doSomething();
// if needed at many places you might want to have a
// convenience function, see below...
at(0)->doSomething();
}
// for convenience of the user you might optionally duplicate
// the const interface of `std::vector` here as well
private:
std::vector<SharedPointer> m_data;
Thing* at(size_t index)
{
return m_data[index].m_data.get();
}
};
int main()
{
DataOwner o;
o.modify();
o.data()[0]->doSomethingElse();
// o.data()[0]->doSomething(); won't compile!
return 0;
}

Related

Can the lifespan of a returning temporary variable be extentended by using move/swap c++11

I have a tree which base node is (not all methods are shown):
struct node_base {
node_base(): _size(0),_parent(NULL) { }
virtual ~node_base() {}
virtual node_iterator_base& begin() const =0;
virtual node_iterator_base& end() const=0;
protected:
size_t _size;
node_base* _parent;
};
From that abstract class you can derive child classes which implement the needed container to hold all child nodes.
As seen I also have a custom iterator node_iterator_base
struct node_iterator_base {
virtual ~node_iterator_base() {}
virtual node_iterator_base& operator++()=0;
virtual node_base* operator->() const =0;
virtual node_base& operator*() const =0;
virtual bool operator==(const node_iterator_base& x) const =0;
virtual bool operator!=(const node_iterator_base& x) const =0;
};
template<It>
struct derived_iterator: public node_iterator_base {
derived_iterator(It I): ci(I) { }
...
It ci;
}
The idea behind these base classes and their derived classes is to make it able to write something like this:
derived_node n;
for(node_iterator_base it=n.begin(); it!=n.end(); it++) {
do_something(*it);
}
Now the problem is to implement begin in the derived class
node_iterator_base& derived_node::begin() const {
return derived_iterator(container);
//This will not work because a temporary variable is passed to a
reference
}
What can be done instead? If we change the declaration of begin to
virtual node_iterator_base begin() const =0;
and
node_iterator_base derived_node::begin() {
return derived_iterator(container);
//This will not work either because node_iterator_base is an abstract struct
}
Of course I could return a pointer but then my iterator will not look like a STL iterator and will have to destroy it manually.
How can I return a reference? Can move/swap from C++11 help me?
More about my heterogeneous tree here
https://www.facebook.com/A-smart-tree-and-a-simple-parser-i-c-1678796648883396
The short answer is no. You cannot do what you want.
The medium answer is yes. You can use the pImpl pattern to pass a facade which holds a pointer to an interface within it; it forwards calls to its implementation interface (pImpl). This permits a seeming value type like an iterator to be polymorphic, at the cost of dynamic allocation and indirection.
The longer answer is that you are attempting to type erase iteration by type erasing iterators. You can do this with pImpl, or something like any or even std function. However, the iterator interface of C++ has a large surface and is interacted with frequently during iteration. Type erasure of iterators has proven expensive. Boost has any iterators that have rolled this for you; they are not suited for use in performance sensitive code.
It may be better to type erase iteration operation itself instead of the iterators. You iterate far less often than you interact with an iterator; by type erasing the less frequent operation you can improve performance significantly (or really, waste less).
Finally, consider using variant instead; if you can enumerate the subclasses, you could use that to give the compiler less indirection and more information.
Any and variant are available in boost or C++17 or can be reimplemented yourself.

Should abstract members of a class be pointers or references?

Should abstract members of a class be pointers or references?
For a toy example, say I have the following class:
class SerializedFileProcessor {
public:
std::string Process(std::string file) const {
std::string text = deserializer.Deserialize(file);
text = processor.Process(text);
return serializer.Serialize(text);
}
private:
IDeserializer? deserializer;
IProcessor? processor;
ISerializer? serializer;
};
Where the (instances of concrete subclasses) deserializer, processor, and serializer are all passed into this class's constructor.
The SerializedFileProcessor doesn't own these and should not delete them.
Should those class members be pointers or references? Or should this pattern be done completely differently?
This is pretty much the hello-world example of dependency injection (/inversion).
There's a similar question here, with different solutions:Dependency injection in C++11 without raw pointers
Edit: I moved my original answer from here into to that question.
Original answer with SerializedFileProcessor example:
The down side of just using a pointer (smart or raw), or even an ordinary C++ reference, is that they allow calling non-const methods from a const context.
I propose a wrapper similar but not identical to std::reference_wrapper (which lacks the const safe accessor). Replace T* with unique_ptr or shared_ptr to get owning versions (also add default move construction).
template<typename T>
struct NonOwningRef{
NonOwningRef() = delete;
NonOwningRef(T& other) noexcept : ptr(std::addressof(other)) { };
NonOwningRef(const NonOwningRef& other) noexcept = default;
const T& value() const noexcept{ return *ptr; };
T& value() noexcept{ return *ptr; };
private:
T* ptr;
};
usage:
class SerializedFileProcessor {
public:
std::string Process(std::string file) const {
std::string text = deserializer.value().Deserialize(file);
text = processor.value().Process(text);
return serializer.value().Serialize(text);
}
private:
NonOwningRef<IDeserializer> deserializer;
NonOwningRef<IProcessor> processor;
NonOwningRef<ISerializer> serializer;
};
They can be either, you must only ensure that the referenced objects do not die before used (i.e. in general its lifetime should exceed the SerializedFileProcessor lifetime).
There is one disadvantage to reference members - it is then virtually impossible to create an assignment operator (so if you need one, then you need a pointer - there are techniques to actually have assignment even for classes with reference members, but they are very nasty). Also in case they are optional, then they need to be pointers (reference is not optional).
If your class doesn't own them, it should not be a reference. Use a pointer and have the owner hold a std::unique_ptr.

C++ Virtual boost::any Inheritance

Basically, I'm trying to write a base class that has a generic iterator in.
So apparently template virtual functions don't work, that's why I tried boost::any, but it is still not overloading Iterator's get() method (it keeps throwing the Exception defined below). I also can't seem to make it pure virtual because the compiler complains about 'virtual iterator begin() = 0;' (it says 'cannot create instance of abstract class Iterator').
I have very specific constraints that I have to / want to adhere to, so alternative solutions to the problem might be looked at, but probably can't be used.
Here is a part of the code:
template <class T, class C>
class Iterator
{
public:
virtual T& operator*() { T *t = boost::any_cast<T>(&get()); return *t; };
virtual boost::any& get() { throw new Exception("get not overridden!!"); };
//virtual boost::any& get() = 0;
protected:
C::iterator iter;
};
template <class T>
class VectorIterator: public Iterator<T, std::vector<T> >
{
public:
VectorIterator(std::vector<T>::iterator iterator): Iterator<T, std::vector<T> >(iterator) { };
virtual boost::any& get() { return *iter; };
};
template <class Value, class Container>
class Repository
{
public:
typedef Iterator<Value, Container> iterator;
virtual iterator begin() = 0;
virtual iterator end() = 0;
};
class SomeRepository : public Repository<RandomClass, std::vector<RandomClass> >
{
public:
iterator begin() { return VectorIterator<RandomClass>(items.begin()); };
iterator end() { return VectorIterator<RandomClass>(items.end()); };
}
So, why isn't it working and (how) can I fix it?
PS: I know this is very similar to another question, but I couldn't exactly fit this into a comment and didn't really know where else I could put it.
UPDATE:
So I managed to figure something out by letting get() return a void (eww) pointer and forgetting about boost::any. But it still calls Iterator::get instead of VectorIterator::get (as was my original problem) (when I try to use something like *someRepository.begin()), does anyone know why?
You cannot initialize a boost::any& from *iter, much like you cannot initialize float& from a value of type int. In both case there is no actual object of the desired type to refer to.
You can change get to return boost::any (in which case the conversion from *iter will happen), but then your operator* has an issue in that the T it wants to refer to (again, reference type) needs to outlive the function call. One solution is to store the result of calling get somewhere, or to follow through with the same change to get by making operator* also return a value (T) rather than a reference (T&). Those would be value semantics, and not a 'shallow' view into the underlying container. Assigning to the result of operator*, assuming it's correct, would not affect the element of the container.
Another possibility is to make get return a boost::any that is guaranteed to store a shallow view into the element, e.g.
virtual boost::any get() { return &*iter; }
(return boost::ref(*iter); is another possibility)
Care must be then taken inside operator* to correctly restore the expected value, e.g. return *boost::any_cast<T*>(get()); (resp. return boot::any_cast<boost::reference_wrapper<T> >(get()).get();). This has reference semantics, where returning T& would be fine. Operations on the result of operator* could potentially affect elements of the container.
If you return Iterator in 'iterator begin()' (so returning by value), it will convert the return to Iterator, thus it will no longer be of type VectorIterator and obviously it will not call VectorIterator's get method (at least that's what I think). Returning by reference or pointer should work just fine.
Now I just need to figure out a workaround. Returning by reference won't work since I'm returning a local variable in VectorIterator::begin(). I suppose I'll have to return by pointer unless someone else has a better suggestion.

C++ : Using different iterator types in subclasses without breaking the inheritance mechanism

I'm trying to achieve the following: Given an abstract class MemoryObject, that every class can inherit from, I have two subclasses: A Buffer and a BigBuffer:
template <typename T>
class MemoryObject
{
public:
typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::const_iterator const_iterator;
[...] //Lot of stuff
virtual iterator begin() = 0;
virtual iterator end() = 0;
};
A Buffer:
template <typename T>
class Buffer: public MemoryObject<T>
{
public:
typedef typename std::vector<T>::iterator iterator;
iterator begin() { return buffer_.begin(); }
iterator end() { return buffer_.end(); };
[...] //Lot of stuff
private:
std::vector<T> buffer_;
};
And finally:
template <typename T>
class BigBuffer: public MemoryObject<T>
{
public:
[...] //Omitted, for now
private:
std::vector<Buffer<T>*> chunks_;
};
As you can see, a BigBuffer holds a std::vector of Buffer<T>*, so you can view a BigBuffer as an aggregation of Buffer(s). Futhermore, I have a bunch of functions that must work of every MemoryObject, so this is a real signature:
template <class KernelType, typename T>
void fill(CommandQueue<KernelType>& queue, MemoryObject<T>& obj, const T& value)
{
//Do something with obj
}
What's the point? - You may ask. The point is that I must implement iterators over these classes. I've already implemented them for Buffer, and is exactly what I need: be able to iterate over a Buffer, and access to ranges (for example b.begin(), b.begin() + 50).
Obviously I can't do the same for BigBuffer, because the real data (that is inside each Buffer' private variable buffer_) is scattered accross the memory. So I need a new class, let's call it BigBufferIterator, which can overload operator like * or +, allowing me to "jump" from a memory chunk to another without incurring in in segmentation fault.
The problems are two:
The iterator type of MemoryObject is different from the iterator
type of BigBuffer: the former is a std::vector<T>::iterator, the
latter a BigBufferIterator. My compiler obviously complains
I want be able to preserve the genericity of my functions signatures
passing to them only a MemoryObject<T>&, not specializing them for
each class type.
I've tried to solve the first problem adding a template parameter classed Iterator, and giving it a default argument to each class, with a model loosely based to Alexandrescu's policy-based model. This solution solved the first issue, but not the second: my compiled still complains, telling me: "Not known conversion from BigBuffer to MemoryObject", when I try to pass a BigBuffer to a function (for example, the fill() ). This is because Iterator types are different..
I'm really sorry for this poem, but It was the only way to proper present my problem to you. I don't know why someone would even bother in reading all this stuff, but I'll take pot luck.
Thanks in advance, only just for having read till this point.
Humbly,
Alfredo
They way to go is to use the most general definition as the iterator type of the base. That is, you want to treat the data in a Buffer as just one segment while the BigBuffer is a sequence of the corresponding segments. This is a bit unfortunate because it means that you treat your iterator for the single buffer in Buffer as if it may be multiple buffers, i.e. you have a segmented structure with just one segment. However, compared to the alternative (i.e. a hierarchy of iterators with virtual functions wrapped by a handle giving value semantics to this mess) you are actually not paying to bad a cost.
I encountered the same problem in a different context; let me restate it.
You have a Base class (which could be abstract), which is iterable via its BaseIterator.
You have a Child subclass, which differs in implementation slightly, and for which you have a different specialized ChildIterator.
You have custom functions that work with Base, and rely on its iterability.
It is not feasible to generate a template specialization of the custom functions for each subclass of Base. Possible reasons may be:
huge code duplication;
you distribute this code as a library and other developers are going to subclass Base;
other classes will take some reference or pointer to Base and apply those custom functions, or more generically:
Base implements some logic that is going to be uses in contexts where do not know any of the subclasses (and writing completely templated code is too cumbersome).
Edit: Another possibility would be using type erasure. You would hide the real iterator that you're using behind a class of a fixed type. You would have to pay the cost of the virtual functions call though. Here is an implementation of a any_iterator class which implements exactly iterator type erasure, and some more background on it.
The only effective solution I could find was to write a multi-purpose iterator that can iterate over all possible containers, possibly exploiting their internals (to avoid copy-pasting the iterator code for every subclass of Base):
// A bigger unit of memory
struct Buffer;
class Iterator {
// This allows you to know which set of methods you need to call
enum {
small_chunks,
big_chunks
} const _granularity;
// Merge the data into a union to save memory
union {
// Data you need to know to iterate over ints
struct {
std::vector<int> const *v;
std::vector<int>::const_iterator it;
} _small_chunks;
// Data you need to know to iterate over buffer chunks
struct {
std::vector<Buffer *> const *v;
std::vector<Buffer *>::const_iterator it;
} _big_chunks;
};
// Every method will have to choose what to do
void increment() {
switch (_granularity) {
case small_chunks:
_small_chunks.it++;
break;
case big_chunks:
_big_chunks.it++;
break;
}
}
public:
// Cctors are almost identical, but different overloads choose
// different granularity
Iterator(std::vector<int> const &container)
: _granularity(small_chunks) // SMALL
{
_small_chunks.v = &container;
_small_chunks.it = container.begin();
}
Iterator(std::vector<Buffer *> const &container)
: _granularity(big_chunks) // BIG
{
_big_chunks.v = &container;
_big_chunks.it = container.begin();
}
// ... Implement all your methods
};
You can use the same class for both Base and Child, but you need to initialize it differently. At this point you can make begin and end virtual and return an Iterator constructed differently in each subclass:
class Base {
public:
virtual Iterator begin() const = 0;
};
class IntChild : public Base {
std::vector<int> _small_mem;
public:
virtual Iterator begin() const {
// Created with granularity 'small_chunks'
return Iterator(_small_mem);
}
// ...
};
class BufferChild : public Base {
std::vector<Buffer *> _big_mem;
public:
virtual Iterator begin() const {
// Created with granularity 'big_chunks'
return Iterator(_big_mem);
}
// ...
};
You will pay a small price in performance (because of the switch statements) and in code duplication, but you will be able to use any generic algorithm from <algorithm>, to use range-loop, to use Base only in every function, and it's not stretching the inheritance mechanism.
// Anywhere, just by knowing Base:
void count_free_chunks(Base &mem) {
// Thanks to polymorphism, this code will always work
// with the right chunk size
for (auto const &item : mem) {
// ...this works
}
// This also works:
return std::count(mem.begin(), mem.end(), 0);
}
Note that the key point here is that begin() and end() must return the same type. The only exception would be if Child's methods would shadow Base's method (which is in general not a good practice).
One possible idea would be to declare an abstract iterator, but this is not so good. You would have to use all the time a reference to the iterator. Iterator though are supposed to be carried around as lightweight types, to be assignable and easily constructible, so it would make coding a minefield.

Call a non-const member function from a const member function

I would like to know if its possible to call a non-const member function from a const member function. In the example below First gives a compiler error. I understand why it gives an error, I would like to know if there is a way to work around it.
class Foo
{
const int& First() const
{
return Second();
}
int& Second()
{
return m_bar;
}
int m_bar;
}
I don't really want to discuss the wisdom of doing this, I'm curious if its even possible.
return (const_cast<Foo*>(this))->Second();
Then cry, quietly.
It is possible:
const int& First() const
{
return const_cast<Foo*>(this)->Second();
}
int& Second() { return m_bar; }
I wouldn't recommend this; it's ugly and dangerous (any use of const_cast is dangerous).
It's better to move as much common functionality as you can into helper functions, then have your const and non-const member functions each do as little work as they need to.
In the case of a simple accessor like this, it's just as easy to return m_bar; from both of the functions as it is to call one function from the other.
By the definition of const, a function should not modify the state of an object. But if it calls another non-const member, the object's state might get changed, so it's disallowed.
I know you said you didn't want to hear about this, but I think it's important for others that happen upon the question.
The restriction of const member methods are came from compile time. If you can fool the compiler, then yes.
class CFoo
{
public:
CFoo() {m_Foo = this;}
void tee();
void bar() const
{
m_Foo->m_val++; // fine
m_Foo->tee(); // fine
}
private:
CFoo * m_Foo;
int m_Val;
};
This actually abolishes the purpose of const member function, so it is better not to do it when design a new class. It is no harm to know that there is a way to do it,especially it can be used as an work-around on these old class that was not well designed on the concept of const member function.
Overload on const:
const int& Second() const
{
return m_bar;
}
You can add this method and keep the original non-const version.
iterators are similar in this and make an interesting study.
const iterators are often the base for 'non const' iterators, and you will often find const_cast<>() or C style casts used to discard const from the base class with accessors in the child.
Edit:
Comment was
I have a zip iterator where the const one inherits from the non-const
This would generally be the wrong inheritence structure (if your saying what I think you are), the reason being that children should not be less restrictive than parents.
say you had some algorithm taking your zip iterator, would it be appropriate to pass a const iterator to a non const ?
if you had a const container, could only ask it for a const iterator, but then the const iterator is derived from an iterator so you just use the features on the parent to have non const access.
Here is a quick outline of suggested inheritence following the traditional stl model
class ConstIterator:
public std::_Bidit< myType, int, const myType *, const mType & >
{
reference operator*() const { return m_p; }
}
class Iterator : public ConstIterator
{
typedef ConstIterator _Mybase;
// overide the types provided by ConstIterator
typedef myType * pointer;
typedef myType & reference;
reference operator*() const
{
return ((reference)**(_Mybase *)this);
}
}
typedef std::reverse_iterator<ConstIterator> ConstReverseIterator;
typedef std::reverse_iterator<Iterator> ReverseIterator;
I found myself trying to call a non-const member function that was inherited, but was actually const because of the API I was using. Finally I settled on a different solution: re-negotiate the API so that the function I inherit is properly const.
It won't always be possible to negotiate changes to others' functions, but doing so when possible seems cleaner and nicer than needing to use const_cast and it benefits other users as well.