I have a class containing a dynamic array and I want to iterate through it using begin() and end(). The problem is that I can't seem to get the iteration part to work correctly. So far it looks something like this:
template<typename T>
class Deque {
T** _deque;
int _front;
int _back;
public:
Deque() {
_deque = new T*[10];
_front = 5;
_back = 5;
}
// push_back and push_front add elements to the list and move _front/_back
// ...
T* begin() {
return _deque[_front];
}
T* end() {
return _deque[_back];
}
};
But if I add a few items to the list with push_back and push_front (which work perfectly) then try this
for (auto i : deque) {
cout << i << endl;
}
The first item will always be correct but all following objects will be garbage and will often exceed the size of the array.
How can I automatically iterate over this structure given it's constrained between _front and _back?
You haven't shown where _deque gets filled in, but it is probably from a whole bunch of separate allocations?
The issue is that to iterate through an array, you need to point into it. But you are reading from the array.
A pointer into _deque would be begin() { return _deque + _front; } end() { return _deque + _back; } and would have type T**.
What you have now is morally equivalent to:
std::vector<T*> v;
...
auto it = *(v.begin()); // this is the first pointer stored *in* the container,
// not a pointer to the beginning of the container
auto end = *(v.end()); // this is not even the last pointer stored in the container,
// it is reading the element past the end!
for( ; it != end; ++it )
which is quite different from the correct iteration:
auto it = v.begin();
auto end = v.end();
for( ; it != end; ++it )
Most likely your _deque variable should have type T*, not T**, and if you want to store pointers, let T be a pointer type.
Related
Since the std::forward_list is implemented as a single-linked list, its iterator should be just a pointer to the underlying element ± some offset.
Is there a way to convert a pointer to an element on a list to the iterator to this element without iterating through the entire list?
#include <forward_list>
template<typename T>
typename std::forward_list<T>::iterator makeIterator(T *element)
{
// magic here
}
int main()
{
std::forward_list<int> list;
list.emplace_front(101);
auto i = makeIterator(&list.front());
return i == list.begin() ? 0 : 1;
}
Short answer: Yes, I could hack a function makeIterator that does that:
template<typename T>
typename std::forward_list<T>::iterator makeIterator(T *element)
{
typedef typename std::forward_list<T>::iterator Iter;
typedef decltype(Iter()._M_node) NodeType;
static int offset = learnOffset<T>();
auto node = reinterpret_cast<NodeType>(reinterpret_cast<uint8_t*>(element) - offset);
return Iter(node);
}
Essentially, it does some pointer arithmetic to derive the address of the underlying list node and constructs an iterator from the derived pointer. The function learnOffset returns the offset needed in the pointer arithmetics.
See the long answer for details on how the function learnOffset is implemented. Note however, that this solution depends on the implementation of your C++ standard library. I am not aware of any public API function that does what you are asking for.
Long answer
I studied the implementation of the forward list iterator in the file /usr/include/c++/11/bits/forward_iterator.h and specifically the implementation of template<typename _Tp> struct _Fwd_list_iterator. It exposes a public member variable that points at the node in the linked list:
_Fwd_list_node_base* _M_node;
and is used for example from the dereferencing operator:
reference
operator*() const noexcept
{ return *static_cast<_Node*>(this->_M_node)->_M_valptr(); }
Reading the source code further suggests that the value stored in a list node is stored by value in the node itself. If so, there should be a constant offset between the pointer to that value and the list node itself. To test that, I wrote the function learnOffset:
template <typename T>
int learnOffset() {
// Populate a list with some data
std::forward_list<T> list;
for (int i = 0; i < 10; i++) {
list.emplace_front(T());
}
// Iterate over the populated list and the address differences
// between the stored element and the list node address held
// by the iterator.
std::unordered_set<int> offsets;
for (auto i = list.begin(); i != list.end(); i++) {
uint8_t* valAddr = reinterpret_cast<uint8_t*>(&(*i));
auto node = reinterpret_cast<uint8_t*>(i._M_node);
offsets.insert(valAddr - node);
}
// We expect exactly one difference. If not, produce an error.
if (offsets.size() != 1) {
std::cerr << "Couldn't learn forward_list iterator offset :-(" << std::endl;
abort();
}
return *(offsets.begin());
}
which returns 8 bytes. We can now directly call this function from the implementation of makeIterator above.
The above implementation of learnOffset leaves a lot to be desired. This code should just be considered a proof-of-concept.
Edited: Made learnOffset a template and to return offset in bytes.
The iterator to a std::forward_list is probaly a Node of the List. Unfortunately there is no compatible way to access the structure of the Node.
If you have a certain compiler and know its underlying Node and iterator implemtation, then you could simply access it with some simple pointer arithmetic.
So, basically yes, possible, but this is of totally incompatible and higly dangerous.
Then, the answer is. With the given prototype of the function, it is not possible.
If you change the prototype of the function and give it a reference to the list, then we can simply iterate along the complete std::forward_list and compare pointers.
This could then look like this:
#include <forward_list>
#include <iostream>
#include <iterator>
template<typename T>
typename std::forward_list<T>::iterator makeIterator(std::forward_list<T>& list, T* element)
{
typename std::forward_list<T>::iterator i = list.begin();
for (; i != list.end(); ++i)
if (&*i == element)
return i;
return i;
}
int main() {
std::forward_list<int> list{};
list.push_front(1);
list.push_front(2);
list.push_front(3);
std::forward_list<int>::iterator iter = std::next(list.begin());
int* valuePtr = &*iter;
std::cout << *valuePtr << '\n';
std::forward_list<int>::iterator calculatedIter = makeIterator(list, valuePtr);
std::cout << *calculatedIter << '\n';
}
It is generally impossible to convert pointers to iterators (without searching the whole container/range). This is only possible for contiguous iterators, and std::forward_list isn't a contiguous container.
I am finding trouble inserting an object into a std::vector, following the example of what I'm trying to do:
//in SomeClass.cpp
void SomeClass::addItem(int32_t &position, OtherClass &value)
{
vectorOtherClass.insert(position,valvalue);
}
however I get the following error when trying to compile the program:
error: no matching function for call to ‘std::vector::insert(int32_t&, OtherClass&)’
vectorOtherClass.insert(position,value);
______________________^
the vector definition in SomeClass.h is:
private:
std::vector<OtherClass> vectorOtherClass;
How can I properly insert an object into a vector in C ++?
And one last question, are the objects stored by reference or by copy within the vector?
Like the error says, there is no insert function with int parameter. See:
single element (1)
iterator insert (iterator position, const value_type& val);
fill (2)
void insert (iterator position, size_type n, const value_type& val);
range (3)
template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);
You can find an example here http://www.cplusplus.com/reference/vector/vector/insert/
int main ()
{
std::vector<int> myvector (3,100);
std::vector<int>::iterator it;
it = myvector.begin();
it = myvector.insert ( it , 200 );
myvector.insert (it,2,300);
// "it" no longer valid, get a new one:
it = myvector.begin();
std::vector<int> anothervector (2,400);
myvector.insert (it+2,anothervector.begin(),anothervector.end());
int myarray [] = { 501,502,503 };
myvector.insert (myvector.begin(), myarray, myarray+3);
std::cout << "myvector contains:";
for (it=myvector.begin(); it<myvector.end(); it++)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
According to the method's reference, the insert method takes the following parameters:
position
Position in the vector where the new elements are inserted.
iterator is a member type, defined as a random access iterator type that points to elements.
val
Value to be copied (or moved) to the inserted elements.
Member type value_type is the type of the elements in the container, defined in deque as an alias of its first template parameter (T).
Note that position is not an integral value, but rather an iterator. C++ use iterators a lot, since many operations are fairly efficient when you have one.
In particular, you can add vector iterators and numbers to get the iterator to the correct position, so you can do something like:
vectorOtherClass.insert(vectorOtherClass.begin() + position, value);
This does not apply to other containers such as std::list. Also, you should make sure to check position is within the bounds of the vector (0 <= position < vectorOtherClass.size()). Ideally, position should be unsigned to ensure the lower bound.
Lastly, elements are added to std::vectors as copies. Vectors use an array internally, so values are copied into it. The array is resized (copied and replaced) as needed.
Refer to: http://en.cppreference.com/w/cpp/container/vector/insert
You need to pass in an interator, so use begin and offset the position from there. No need to pass in ints by ref unless your function is going to change them. Consider checking for buffer overflow.
void SomeClass::addItem(int32_t position, const OtherClass &value)
{
assert(position < vectorOtherClass.size());
assert(position >= 0);
vectorOtherClass.insert(vectorOtherClass.begin()+position, value);
}
I have a large size of vector and I want extract its subvector based on index. But I do not want to make a new copy of a subvector.
Can I use pointer a iterator to return the pointer of the original vector?
something like:
vector<int> orig = { 0,1,2,3,4,5,6,7,8,9 };
vector<int> index = { 3,5,6,8 };
vector<int> dest (vector<int> orig, vector<int> index)
{
....
}
What I want get is get dest as { 3,5,6,8 } and it is point to orig but not the new copy.
(index is the index vector of what I want to extract from the original vector)
Or, can I use smart pointer to do this?
You won't be able to create a std::vector<T> from a subrange of another std::vector<T>. However, you could travel in terms of a view which stores iterators into a std::vector<T> which is owning the actual values:
template <typename Iterator>
class array_view {
Iterator begin_;
Iterator end_;
public:
// ...
array_view(Iterator begin, Iterator end): begin_(begin), end_(end) {}
Iterator begin() const { return this->begin_; }
Iterator end() const { return this->end_; }
typename std::iterator_traits<Iterator>::reference
operator[](std::size_t index) { return this->begin_[index]; }
};
Things get a bit interesting if you want to deal with the same type independently of who owns the actual array. In that case you might want to create something like the array_view<T> above but also storing a std::shared_ptr<std::vector<T>> for the underlying representation (and if you need to modify the original representation, you'd store offsets instead of iterators).
Every time I say I've sworn off std::valarray, somebody brings up a problem like this that valarray supports quite directly. For example:
std::valarray<int> orig = { 0,1,2,3,4,5,6,7,8,9 };
std::valarray<size_t> index = { 3,5,6,8 };
orig[index] = -1;
Then if (for example) we print out the elements of orig with code like this:
for (int i=0; i<orig.size(); i++)
std::cout << orig[i] << "\t";
... we get the following results:
0 1 2 -1 4 -1 -1 7 -1 9
If you want the vector to be mutable, no. If you just want to pass a subvector around but not change the contents, why not change your various functions to take a start and end iterator rather than be passed a vector?
I would like to make a method that has for argument a pointer to the first element of an array, and that then cycles through the array looking for something...
void MyClass::myMethod(T *x)
{
// I know that *x points to the first entry in a properly defined array.
// I want to cycle through this array, and try to find a member T of that array that
// meets certain criteria.
// I would then like to store a pointer to this T that meets my criteria.
}
You also need to pass the size of the array explicitly. Then you can do:
for(T *current = x; current < x + count; ++current) {
// do something with current, compare or whatever
}
An alternative would be to use indexing notation, like below. Which one is better mainly depends on how exactly you want to access the data later on.
for(int i = 0; i < count; ++i) {
// current element is x[i]
// pointer to current element is then x+i, or &x[i]
}
Usually you are better off using standard array containers, implementing your algorithms using iterators. Your function then takes two iterators defining the range on which it should operate, basically like this:
template<typename Iterator>
void doSomething(Iterator begin, Iterator end) {
for(; begin != end; ++begin) {
// current element is *begin
}
}
instead of using pointers. Create a vector and use find_if to return the iterator(position ) of the element of interest and do your processing.
So I've got a list:
list<Object> myList;
myList.push_back(Object myObject);
I'm not sure but I'm confident that this would be the "0th" element in the array.
Is there any function I can use that will return "myObject"?
Object copy = myList.find_element(0);
?
If you frequently need to access the Nth element of a sequence, std::list, which is implemented as a doubly linked list, is probably not the right choice. std::vector or std::deque would likely be better.
That said, you can get an iterator to the Nth element using std::advance:
std::list<Object> l;
// add elements to list 'l'...
unsigned N = /* index of the element you want to retrieve */;
if (l.size() > N)
{
std::list<Object>::iterator it = l.begin();
std::advance(it, N);
// 'it' points to the element at index 'N'
}
For a container that doesn't provide random access, like std::list, std::advance calls operator++ on the iterator N times. Alternatively, if your Standard Library implementation provides it, you may call std::next:
if (l.size() > N)
{
std::list<Object>::iterator it = std::next(l.begin(), N);
}
std::next is effectively wraps a call to std::advance, making it easier to advance an iterator N times with fewer lines of code and fewer mutable variables. std::next was added in C++11.
std::list doesn't provide any function to get element given an index. You may try to get it by writing some code, which I wouldn't recommend, because that would be inefficient if you frequently need to do so.
What you need is : std::vector. Use it as:
std::vector<Object> objects;
objects.push_back(myObject);
Object const & x = objects[0]; //index isn't checked
Object const & y = objects.at(0); //index is checked
std::list<Object> l;
std::list<Object>::iterator ptr;
int i;
for( i = 0 , ptr = l.begin() ; i < N && ptr != l.end() ; i++ , ptr++ );
if( ptr == l.end() ) {
// list too short
} else {
// 'ptr' points to N-th element of list
}
Maybe not the most efficient way. But you could convert the list into a vector.
#include <list>
#include <vector>
list<Object> myList;
vector<Object> myVector(myList.begin(), myList.end());
Then access the vector using the [x] operator.
auto x = MyVector[0];
You could put that in a helper function:
#include <memory>
#include <vector>
#include <list>
template<class T>
shared_ptr<vector<T>>
ListToVector(list<T> List) {
shared_ptr<vector<T>> Vector {
new vector<string>(List.begin(), List.end()) }
return Vector;
}
Then use the helper funciton like this:
auto MyVector = ListToVector(Object);
auto x = MyVector[0];
Not very efficient, but if you must use a list, you can deference the iterator
*myList.begin()+N