I want to implement a sorted pointer vector, like the following
#include <vector>
#include <memory>
#include <algorithm>
//! A random accessed vector with sorted allocated elements.
//! - Elements must be allocated on heap.
//! - The vector manages the memories of its elements.
template<class T, class Compare = std::less<T>>
class SortedPtrVector
{
public:
SortedPtrVector() {}
//! Add an element, return its index.
int Add(T* element)
{
auto position = std::lower_bound(m_vector.begin(), m_vector.end(),
element, Compare); // Wrong here due to compare smart pointers
auto newPosition = m_vector.insert(position, element);
return newPosition - m_vector.begin();
}
private:
std::vector<std::unique_ptr<T>> m_vector;
};
How to implement the Add function? Thanks a lot.
auto position = std::lower_bound(m_vector.begin(), m_vector.end(),
element, Compare);
This is obviously wrong. Compare is a type, not an object.
You could use lambda with an object of Compare. So I think this should work:
Compare cmp;
auto comparer = [&](std::unique_ptr<T> const & a, std::unique_ptr<T> const & b)
{
return cmp(*a, *b); //use cmp here!
};
std::unique_ptr<T> uniqElem(element);
auto position = std::lower_bound( m_vector.begin(),
m_vector.end(),
uniqElem, //not element!!
comparer);
Note that you cannot pass element to std::lower_bound, as element is of type T*, when the std::lower_bound expects the value of type std::unique_ptr<T> and there is no implicit conversion from T* to std::unique_ptr<T>. Also, you cannot insert element to the vector for the same reason. Insert uniqElem to the vector.
I would suggest you to take the argument as unique_ptr instead of T*, because that indicates to the user that the added item will be deleted automatically when an object of SortedPtrVector goes out of scope:
int Add(T* element); //bad - doesn't say element will be deleted!
int Add(std::unique_ptr<T> element); //good - says element will be deleted!
If you use std::unique_ptr<T> as parameter type, then note these points:
v.Add(new T()); //will not work
v.Add(std::unique_ptr<T>(new T()); //will work
std::unique_ptr<T> item(new T());
v.Add(item); //will not work
v.Add(std::move(item)); //will work
It is all because std::unique_ptr is NOT copyable, but it is moveable.
Instead of using std::less you can implement your own ptr_less like this:
template< typename T >
class ptr_less
{
typedef bool result_type;
bool operator ()( T const& left, T const& right ) const
{
return *left < *right;
}
};
A general implementation would have to check for null pointers as well.
Another approach would be to use boost::ptr_vector instead of std::vector.
Related
I need to make use of a queue of doubles because of the good properties it has as an ordered container. I want to pass this queue to a class constructor that accepts vectors. If I do that directly I get the following error:
candidate constructor not viable: no known conversion from
'std::queue' to 'std::vector &' for 2nd argument
How to cast a queue to a vector?
The correct container to model both queue_like behaviour and vector-like behaviour is a std::deque.
This has the advantages of:
constant-time insertion and deletion at either end of the deque
ability to iterate elements without destroying the deque
std::deque supports the begin() and end() methods which means you can construct a vector (with compatible value-type) directly.
#include <vector>
#include <deque>
class AcceptsVectors
{
public:
AcceptsVectors(std::vector<double> arg);
};
int main()
{
std::deque<double> myqueue;
auto av = AcceptsVectors({myqueue.begin(), myqueue.end()});
}
A non-mutating conversion of a queue to a vector is not possible.
I don't think there's any direct way available.
Hence this can be achieved by adding elements one by one to the vector.
std::vector<int> v;
while (!q.empty())
{
v.push_back(q.front());
q.pop();
}
Note that the queue will be empty after this.
As suggested by #David in the comment, it'd be good to avoid copying the queue elements (helpful especially when the contained objects are big). Use emplace_back() with std::move() to achieve the same:
v.emplace_back(std::move(q.front()));
std::vector has a constructor taking a pair of iterators, so if you would be able to iterate over the queue, you would be set.
Borrowing from an answer to this question, you can indeed do this by subclassing std::queue:
template<typename T, typename Container=std::deque<T> >
class iterable_queue : public std::queue<T,Container>
{
public:
typedef typename Container::const_iterator const_iterator;
const_iterator begin() const { return this->c.begin(); }
const_iterator end() const { return this->c.end(); }
};
(Note we're allowing only const iteration; for the purpose in the question, we don't need iterators allowing modifying elements.)
With this, it's easy to construct a vector:
#include <queue>
#include <vector>
using namespace std;
template<typename T, typename Container=std::deque<T> >
class iterable_queue : public std::queue<T,Container>
{
public:
typedef typename Container::const_iterator const_iterator;
const_iterator begin() const { return this->c.begin(); }
const_iterator end() const { return this->c.end(); }
};
int main() {
iterable_queue<int> int_queue;
for(int i=0; i<10; ++i)
int_queue.push(i);
vector<int> v(int_queue.begin(), int_queue.end());
return 0;
}
This is just an approach to avoid copying from std::queue to std::vector. I leave it up to you, if to use it or not.
Premises
std::queue is a container adaptor. The internal container by default is std::deque, however you can set it to std::vector as well. The member variable which holds this container is marked as protected luckily. Hence you can hack it by subclassing the queue.
Solution (!)
template<typename T>
struct my_queue : std::queue<T, std::vector<T>>
{
using std::queue<T, std::vector<T>>::queue;
// in G++, the variable name is `c`, but it may or may not differ
std::vector<T>& to_vector () { return this->c; }
};
That's it!!
Usage
my_queue<int> q;
q.push(1);
q.push(2);
std::vector<int>& v = q.to_vector();
Demo.
I tried to simplify the situation as good as possible.
Basically I have a class that represents a dynamic Array (here shown as class Array with size 4) and secondly a class which is a HashMap, and has an Array of Arrays as a member (here represented by class Bar).
Both classes implement begin() and end() so you can use a foreach loop to iterate over all elements.
The iterator type of Array is simply T* and const T* for the const variant.
For Bar there is a special class Iterator, which correctly iterates through all members of the Array<Array<T>>.
You should now have a look at the classes I provided, so you know what exactly I'm talking about.
But now there is a problem when I call bar.begin() on a const Bar object
The Iterator class determines the ArrayIterator and ElementIterator types automatically (via decltype of T::begin()), because in my real application almost everything is templated and that's why I don't know the exact type in advance.
I figured out the problem is that decltype(((T*)nullptr)->begin()) always chooses the non-const begin() function of T, which absolutely makes sense since I haven't written (const T*)nullptr.
If I now call it from a const context, it will fail to assign a const T* like data.last().end() to the internal T* from the decltype which actually should be a const T*.
I can workaround the problem by declaring a second class ConstIterator which does everything exactly like the non-const one, but uses (const Array<T>*)nullptr and (const T*)nullptr inside the decltype statements.
So what can I do without copying the whole Bar::Iterator class?
Simplified code:
template<class T>
class Array
{
T data[4];
T last() { return data[3]; }
T* begin() { return data; };
T* end() { return data + 4; };
const T* begin() const { return data; };
const T* end() const { return data + 4; };
}
template<class T>
class Bar
{
class Iterator
{
using ArrayIterator = decltype(((Array<T>*)nullptr)->begin());
using ElementIterator = decltype(((T*)nullptr)->begin());
Iterator(const ArrayIterator& beg, const ArrayIterator& end)
{
//initialize the iterator to the first element of the first array
//(and rembember end)
};
Iterator(const ElementIterator& cur)
{
//initialize the iterator to the current element
};
//++ will iterate go to next element and eventually jump to the next array.
//== returns true if the current element is the same
};
Array<T> data;
Iterator begin() { return Iterator(data.begin(), data.end()); };
Iterator end() { return Iterator(data.last().end()); };
Iterator begin() const { return Iterator(data.begin(), data.end()); };
Iterator end() const { return Iterator(data.last().end()); };
};
Actually, you will have to implement ConstIterator class. See, for example, the standard containers like vector or list, you have both iterator and const_iterator there, and they're different classes. Const correctness is hard sometimes. However, you can get away with code duplication by using templates or const_cast (see, for example, Scott Myers Effective C++)
I have a C++ class that acts like a container: it has size() and operator[] member functions. The values stored "in" the container are std::tuple objects. However, the container doesn't actually hold the tuples in memory; instead, it constructs them on-demand based on underlying data stored in a different form.
std::tuple<int, int, int>
MyContainer::operator[](std::size_t n) const {
// Example: draw corresponding elements from parallel arrays
return { underlying_data_a[n], underlying_data_b[n], underlying_data_c[n] };
}
Hence, the return type of operator[] is a temporary object, not a reference. (This means it's not an lvalue, so the container is read-only; that's OK.)
Now I'm writing an iterator class that can be used to traverse the tuples in this container. I'd like to model RandomAccessIterator, which depends on InputIterator, but InputIterator requires support for the expression i->m (where i is an iterator instance), and as far as I can tell, an operator-> function is required to return a pointer.
Naturally, I can't return a pointer to a temporary tuple that's constructed on-demand. One possibility that comes to mind is to put a tuple instance into the iterator as a member variable, and use it to store a copy of whichever value the iterator is currently positioned on:
class Iterator {
private:
MyContainer *container;
std::size_t current_index;
// Copy of (*container)[current_index]
std::tuple<int, int, int> current_value;
// ...
};
However, updating the stored value will require the iterator to check whether its current index is less than the container's size, so that a past-the-end iterator doesn't cause undefined behavior by accessing past the end of the underlying arrays. That adds (a small amount of) runtime overhead — not enough to make the solution impractical, of course, but it feels a little inelegant. The iterator shouldn't really need to store anything but a pointer to the container it's iterating and the current position within it.
Is there a clean, well-established way to support operator-> for iterator types that construct their values on-demand? How would other developers do this sort of thing?
(Note that I don't really need to support operator-> at all — I'm implementing the iterator mainly so that the container can be traversed with a C++11 "range for" loop, and std::tuple doesn't have any members that one would typically want to access via -> anyway. But I'd like to model the iterator concepts properly nonetheless; it feels like I'm cutting corners otherwise. Or should I just not bother?)
template<class T>
struct pseudo_ptr {
T t;
T operator*()&&{return t;}
T* operator->(){ return &t; }
};
then
struct bar { int x,y; };
struct bar_iterator:std::iterator< blah, blah >{
// ...
pseudo_ptr<bar> operator->() const { return {**this}; }
// ...
};
This relies on how -> works.
ptr->b for pointer ptr is simply (*ptr).b.
Otherwise it is defined as (ptr.operator->())->b. This evaluates recursively if operator-> does not return a pointer.
The pseudo_ptr<T> above gives you a wrapper around a copy of T.
Note, however, that lifetime extension doesn't really work. The result is fragile.
Here's an example relying on the fact that operator-> is applied repeatedly until a pointer is returned. We make Iterator::operator-> return the Contained object as a temporary. This causes the compiler to reapply operator->. We then make Contained::operator-> simply return a pointer to itself. Note that if we don't want to put operator-> in the Contained on-the-fly object, we can wrap it in a helper object that returns a pointer to the internal Contained object.
#include <cstddef>
#include <iostream>
class Contained {
public:
Contained(int a_, int b_) : a(a_), b(b_) {}
const Contained *operator->() {
return this;
}
const int a, b;
};
class MyContainer {
public:
class Iterator {
friend class MyContainer;
public:
friend bool operator!=(const Iterator &it1, const Iterator &it2) {
return it1.current_index != it2.current_index;
}
private:
Iterator(const MyContainer *c, std::size_t ind) : container(c), current_index(ind) {}
public:
Iterator &operator++() {
++current_index;
return *this;
}
// -> is reapplied, since this returns a non-pointer.
Contained operator->() {
return Contained(container->underlying_data_a[current_index], container->underlying_data_b[current_index]);
}
Contained operator*() {
return Contained(container->underlying_data_a[current_index], container->underlying_data_b[current_index]);
}
private:
const MyContainer *const container;
std::size_t current_index;
};
public:
MyContainer() {
for (int i = 0; i < 10; i++) {
underlying_data_a[i] = underlying_data_b[i] = i;
}
}
Iterator begin() const {
return Iterator(this, 0);
}
Iterator end() const {
return Iterator(this, 10);
}
private:
int underlying_data_a[10];
int underlying_data_b[10];
};
int
main() {
MyContainer c;
for (const auto &e : c) {
std::cout << e.a << ", " << e.b << std::endl;
}
}
I have a vector< Object > myvec which I use in my code to hold a list of objects in memory. I keep a pointer to the current object in that vector in the "normal" C fashion by using
Object* pObj = &myvec[index];
This all works fine if... myvec doesn't grow big enough that it is moved around during a push_back at which time pObj becomes invalid - vectors guarantee data is sequential, hence they make no effort to keep the vector at the same memory location.
I can reserve enough space for myvec to prevent this, but I dnt' like that solution.
I could keep the index of the selected myvec position and when I need to use it just access it directly, but it's a costly modification to my code.
I'm wondering if iterators keep the their references intact as a vector is reallocated/moved and if so can I just replace
Object* pObj = &myvec[index];
by something like
vector<Object>::iterator = myvec.begin()+index;
What are the implication of this?
Is this doable?
What is the standard pattern to save pointers to vector positions?
Cheers
No... using an iterator you would have the same exact problem. If a vector reallocation is performed then all iterators are invalidated and using them is Undefined Behavior.
The only solution that is reallocation-resistant with an std::vector is using the integer index.
Using for example std::list things are different, but also the are different efficiency compromises, so it really depends on what you need to do.
Another option would be to create your own "smart index" class, that stores a reference to the vector and the index. This way you could keep just passing around one "pointer" (and you could implement pointer semantic for it) but the code wouldn't suffer from reallocation risks.
Iterators are (potentially) invalidated by anything that could resize the vector (e.g., push_back).
You could, however, create your own iterator class that stored the vector and an index, which would be stable across operations that resized the vector:
#include <iterator>
#include <algorithm>
#include <iostream>
#include <vector>
namespace stable {
template <class T, class Dist=ptrdiff_t, class Ptr = T*, class Ref = T&>
class iterator : public std::iterator<std::random_access_iterator_tag, T, Dist, Ptr, Ref>
{
T &container_;
size_t index_;
public:
iterator(T &container, size_t index) : container_(container), index_(index) {}
iterator operator++() { ++index_; return *this; }
iterator operator++(int) { iterator temp(*this); ++index_; return temp; }
iterator operator--() { --index_; return *this; }
iterator operator--(int) { stable_itertor temp(*this); --index_; return temp; }
iterator operator+(Dist offset) { return iterator(container_, index_ + offset); }
iterator operator-(Dist offset) { return iterator(container_, index_ - offset); }
bool operator!=(iterator const &other) const { return index_ != other.index_; }
bool operator==(iterator const &other) const { return index_ == other.index_; }
bool operator<(iterator const &other) const { return index_ < other.index_; }
bool operator>(iterator const &other) const { return index_ > other.index_; }
typename T::value_type &operator *() { return container_[index_]; }
typename T::value_type &operator[](size_t index) { return container_[index_ + index]; }
};
template <class T>
iterator<T> begin(T &container) { return iterator<T>(container, 0); }
template <class T>
iterator<T> end(T &container) { return iterator<T>(container, container.size()); }
}
#ifdef TEST
int main() {
std::vector<int> data;
// add some data to the container:
for (int i=0; i<10; i++)
data.push_back(i);
// get iterators to the beginning/end:
stable::iterator<std::vector<int> > b = stable::begin(data);
stable::iterator<std::vector<int> > e = stable::end(data);
// add enough more data that the container will (probably) be resized:
for (int i=10; i<10000; i++)
data.push_back(i);
// Use the previously-obtained iterators:
std::copy(b, e, std::ostream_iterator<int>(std::cout, "\n"));
// These iterators also support most pointer-like operations:
std::cout << *(b+125) << "\n";
std::cout << b[150] << "\n";
return 0;
}
#endif
Since we can't embed this as a nested class inside of the container like a normal iterator class, this requires a slightly different syntax to declare/define an object of this type; instead of the usual std::vector<int>::iterator whatever;, we have to use stable::iterator<std::vector<int> > whatever;. Likewise, to obtain the beginning of a container, we use stable::begin(container).
There is one point that may be a bit surprising (at least at first): when you obtain a stable::end(container), that gets you the end of the container at that time. As shown in the test code above, if you later add more items to the container, the iterator your obtained previously is not adjusted to reflect the new end of the container -- it retains the position it had when you obtained it (i.e., the position that was the end of the container at that time, but isn't any more).
No, iterators are invalidated after vector growth.
The way to get around this problem is to keep the index to the item, not a pointer or iterator to it. This is because the item stays at its index, even if the vector grows, assuming of course that you don't insert any items before it (thus changing its index).
I'm writing some C++ code that manipulates a bunch of vectors that are changing in size and are thus being reallocated constantly.
I would like to get a "pointer" into these vectors that remains valid even after reallocation of the vector. More specifically, I just want these "pointers" to remember which vector they point into and the index to which they point. When I dereference them using the standard (*ptr) syntax, I just want them to do the obvious lookup.
Obviously, actual pointers will not be valid after reallocation, and my understanding is that iterators aren't valid after reallocation either. Note also that I don't care if elements are inserted before my objects, so these "pointers" really don't have to remember anything but a vector and an index.
Now, I could easily write such a class myself. Has anyone (Boost? STL?) done it for me already?
Edit: The answers don't address my question. I asked if this functionality is any standard library. I take the responses as a "no"?
Try a std::pair< vector*, int>, as neither the position of the vector nor the index of the element changes.
Or, as a class:
template<class T> class VectorElementPointer
{
vector<T>& vectorref;
typename vector<T>::size_type index;
public:
VectorElementPointer(vector<T>& vref, typename vector<T>::size_type index):vectorref(vref),index(index){}
T& operator*() const {return vectorref[index];}
T* operator->() const {return &vectorref[index];}
};
This is the easiest solution that comes to my mind, as neither the STL nor Boost contains anything to do it easier.
An article on persistent iterators, complete with implementation.
To summarize some ideas. Here is the minimalist wrapper that tries to mimic iterators but stay valid as opposite to vector's ones.
void print(const std::string& i)
{
std::cout << "<" << i << "> ";
}
int main()
{
typedef std::vector<std::string> Vector;
Vector v;
v.push_back("H");
v.push_back("E");
v.push_back("W");
StrongIterator<Vector> it0(v, 0);
StrongIterator<Vector> it3(v, v.end());
std::for_each(it0.it(), it3.it(), print);
std::cout << std::endl;
v.push_back("O");
std::for_each(it0.it(), it3.it(), print);
std::cout << *it0;
std::cout << it0->c_str();
return 0;
}
And the iterator itself.
template <typename TVector>
class StrongIterator
{
public:
typedef typename TVector::iterator iterator;
typedef typename TVector::size_type size_type;
typedef typename TVector::value_type value_type;
StrongIterator(TVector& vector,
size_type index):
vector_(vector),
index_(index)
{}
StrongIterator(TVector& vector,
iterator it):
vector_(vector),
index_(std::distance(vector.begin(), it))
{}
iterator it()
{
iterator it = vector_.begin();
std::advance(it, index_);
return it;
}
value_type& operator*()
{
return vector_[index_];
}
value_type* operator->()
{
return &vector_[index_];
}
private:
TVector& vector_;
size_type index_;
};
Unfortunately, once you modify the vector, the iterators that would "point" to an element of the vector are no longer guaranteed to be valid. The only STL structure that I know of which will keep the iterators valid even as the structure is changing is the list<>. If you only want sequential iteration of your structures than you can use std::list<> otherwise I do not know of any other library that can help you; that doesn't mean there isn't one.
Here's some clear documentation on std::list : http://www.cplusplus.com/reference/stl/list/
Using boost::iterator_facade :
// Warning: Untested, not even compiled
template<class VectorT>
class VectorIndex :
public boost::iterator_facade<VectorIndex, typename VectorT::reference, boost::random_access_traversal_tag>
{
public:
VectorIndex(VectorT& Vec, typename VectorT::size_type Index)
: m_Vec(Vec), m_Index(Index)
{
}
private:
friend class boost::iterator_core_access;
void increment()
{
++m_Index;
}
void decrement()
{
--m_Index;
}
void advance(difference_type N)
{
m_Index += N;
}
difference_type distance_to(const VectorIndex& Other)
{
assert(&this->m_Vec == &Other.m_Vec);
return Other.m_Index = this->m_Index;
}
bool equal(const VectorIndex& Other)const
{
return (this->m_Vec == Other.m_Vec)
&& (this->m_Index == Other.m_Index);
}
VectorT::reference dereference() const
{
return m_Vec[m_Index];
}
VectorT m_Vec;
VectorT::size_type m_Index;
};
Unless you write your own version of vector and smart pointer there is no way that a pointer will be valid after a reallocation. If you had your own implementations the smart vector could send notifications to your smart pointers.
However I think that the whole scenario is a bad design and you might be better of redesigning your scenario so that you don't have a requirement like that.
Depending on your use pattern, a std::deque may fufil your requirements. Pointers into a deque are only invalidated if you insert or delete items not at the beginning or end - in pother words push_front() and push_back() don't invalidate pointers into the deque, but other changes do. You get basically the same interface as a vector, but of course the underlying storage is not contiguous.