Im trying to create an iterator for my dynamic vector class that i've implemented,
The thing is I keep getting this error when I try to initilaize some student class for testing
purposes on some assignment for the iterator, I cannot figure out why Im having this error wasted alot of hours on it and its impossible to figure out why this error occurs..
Here is the code
some edit
Here is the main function that im trying to use that takes the iterator from my class
some edit
Just in the intiliaze of the DYNVECTOR class in the main my code fails , I keep on getting
the error:
error: cannot convert 'Student*' to 'DYNVECTOR <Student, 24>::Node*' in initialization
Iter(T *N ) : _pointer(N) { }
EDIT: please guys focus on this part:
inputIterator begin() { return inputIterator(pa);}
this is what is causing the error, the functionality of the push back function and other funtions are still in progress but that is not the reason causing this error.
The Problem
inputIterator begin() { return inputIterator(pa);}
is calling inputIterator's constructor
Iter(T *N ) : _pointer(N) { }
with a pointer to a T, a T *. Iter takes T * happily, but it tries to store that T * into _pointer and _pointer is defined as
Node *_pointer;
which is NOT a T *. The assignment fails because the types don't match.
The Naive Solution
Make the types match. This means you have to pass in a Node *. Bad news: DYNARRAY doesn't have any Node *s to give it. Naive solution fails.
The Proper Solution
Throw out Node. Node is useful if you have a linked list. You don't have a linked list. Kill it. Make it dead. Clean up the mess.
class DYNVECTOR
{
// no nodes
class Iter // directly uses T pointers
{
public:
Iter(T *N) :
_pointer(N) // types match now
{
}
T& operator*() const
{
return *_pointer; // simpler without Node, no?
}
T* operator->() const
{
return _pointer; // simple
}
Iter& operator++()
{
_pointer++; // dead simple
return *this;
}
Iter operator++(int)
{
Iter tmp = *this;
_pointer++; // yawn-city
return tmp;
}
bool operator==(Iter const &rhs) const
{
return _pointer == rhs._pointer; // unchanged
}
bool operator!=(Iter const &rhs) const
{
return _pointer != rhs._pointer; // unchanged
}
private:
T *_pointer; // T *, not Node *
};
private:
size_t someCap, length; //, initCap; don't see the point of initCap
T *pa; // unchanged
public:
typedef Iter inputIterator;
DYNVECTOR():
someCap(Capacity), // Still not sure what Capacity is for, so I used
// it here instead of magic number 24
length(0),
pa(new T[someCap])
{
// used initializer list instead.
}
inputIterator begin()
{
return inputIterator(pa); // unchanged
}
inputIterator end()
{
return inputIterator(&pa[length]); // iterator to one past the end.
// just like std::vector
}
template<class Iter>
DYNVECTOR(const Iter &begin, const Iter &end): // far more versatile if const references
DYNVECTOR() // delegate basic set-up to default constructor
{
for (Iter pointer = begin; pointer != end; pointer++) // loop unchanged
{
push_back(*pointer);
}
}
// make uncopyable (for now anyway) See Rule of Three
// linked below for why
DYNVECTOR(const DYNVECTOR & ) = delete;
DYNVECTOR& operator=(const DYNVECTOR & ) = delete;
~DYNVECTOR() // for my own testing. left as example
{
delete[] pa; // clean up allocated storage
}
void push_back(const T & newb) // for my own testing. left as example
{
if (length == someCap) // need more space
{
int newCap = someCap * 2; // double the size
// you might need to do something different like
// int newCap = someCap + Capacity;
// There's no way for me to know.
// The rest should be right though.
T* newArr = new T[newCap]; // allocate bigger array
for (size_t index = 0; index < length; index++)
{ // copy old array into new
newArr[index] = pa[index];
}
delete[] pa; // discard old array
pa = newArr; // use new array
someCap = newCap; // update capacity
}
pa[length] = newb; // insert new item
length++; // update counter
}
};
Documentation on the Rule of Three and friends. You cannot write complex and efficient C++ unless you understand these rules. Learn them or consign yourself to being a hack.
First of all when you deal with objects it is bad practice to do:
DYNVECTOR<Student, 24> students;
It should be:
DYNVECTOR<Student*, 24> students;
Secondly you never created a constructor for your DYNVECTOR how do you expect the object to be created??
Related
Hi i am reading C++ primer 5th addition and have some doubts in the section of weak_ptr. It is written that
By using a weak_ptr, we don’t affect the lifetime of the vector to which a given StrBlob points. However, we can prevent the user from attempting to access a vector that no longer exists.
Then they have given the following code as an example:
#include<iostream>
#include<string>
#include<vector>
#include<memory>
#include<initializer_list>
using namespace std;
class StrBlobPtr;
class StrBlob {
friend class StrBlobPtr;
public:
typedef std::vector<std::string>::size_type size_type;
StrBlob():data(std::make_shared<std::vector<std::string>>()){
}
StrBlob(std::initializer_list<std::string> il):data(make_shared<vector<std::string>>(il)){
}
size_type size() const {
return data->size();
}
bool empty() const {
return data->empty();
}
void push_back(const std::string &t){
data->push_back(t);
}
std::string& front(){
check(0,"front on empty StrBlob");
return data->front();
}
std::string& front() const{
check(0,"front on const empty StrBlob");
return data->front();
}
std::string& back(){
check(0,"back on empty StrBlob");
return data->back();
}
std::string& back() const {
check(0,"back on const empty StrBlob");
return data->back();
}
void pop_back(){
check(0,"pop_back on empty StrBlob");
data->pop_back();
}
private:
std::shared_ptr<std::vector<std::string>> data;
void check(size_type i, const std::string &msg) const{
if(i >= data->size()){
throw out_of_range(msg);
}
}
StrBlobPtr begin();
StrBlobPtr end();
};
class StrBlobPtr {
public:
typedef std::vector<std::string>::size_type size_type;
StrBlobPtr():curr(0){
}
StrBlobPtr(StrBlob &a, size_type sz = 0):wptr(a.data), curr(sz){
}
std::string& deref() const {
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobPtr& incr(){
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
std::shared_ptr<std::vector<std::string>> check(std::size_t i, const std::string &msg) const{
auto ret = wptr.lock();
if(!ret){
throw std::runtime_error("unbound StrBlobPtr");
}
if(i>= ret->size()){
throw std::out_of_range(msg);
}
return ret;
}
private:
std::weak_ptr<std::vector<std::string>> wptr;
size_type curr;
};
StrBlobPtr StrBlob::begin() {
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end() {
auto ret = StrBlobPtr(*this, data->size());
}
int main(){
return 0;
}
My questions are as follows:
How can we prevent the user from attempting to access a vector that no longer exists? I can't come up with a use case,how can we use the above quoted statement in this example?
How does this example shows/verifies that we can prevent the user from attempting to access a vector that no longer exists? *If this example does not shows what they have written then why is this example there in the book?*Note that i have written if.
1. How can we prevent the user from attempting to access a vector that no longer exists?
We can prevent it by exchanging a weak_ptr for a shared_ptr. weak_ptr::lock() does that. It atomically checks if the pointed-to object still exists and increments the corresponding shared_ptr ref count, thus "blocking" any possible deletion from that point on.
So after this line:
auto ret = wptr.lock();
ret will be a shared_ptr that either owns the object or doesn't, and that fact will not change for as long as ret exists.
Then with a simple test you can safely check if there is an object or not:
if(!ret){
/* no object anymore */
}
At the end the function does return ret;, which returns a copy of it, thus still preventing an object from being deleted (ref count is again incremented and then decremented). So as long as you own an instance of shared_ptr, you can rest assured the object will continue to exist.
However, here we have a problem:
std::string& deref() const {
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
This returns a reference to std::string inside a vector which, after p goes out of scope is held only by weak_ptr, i.e. a potentially dangling reference (which is no different from a dangling pointer).
2. How does this example shows/verifies that we can prevent the user from attempting to access a vector that no longer exists?
Apparently it doesn't. Just ignore it.
I am working on a homework assignment where we are supposed to implement a set using a hash based chain implementation.
We are using C++'s forward_list for the buckets.
We have to overload operators + for union, * for intersection, and the assignment operator (=). But every time I run my program, I get this error.
Exception thrown: read access violation.
_Pnext was 0xDDDDDDE1.
This code gives me the error. Specifically the last line
SetT<int> setA;
SetT<int> setB;
SetT<int> setResult;
setA.Add(20);
setB.Add(20);
setResult = setA * setB;
I tried debugging, but it didn't help.
It would go through the operator* with no problems, then it would go through the operator=, exit, and then as soon as I got back to main to go to the next line, it would give me the error.
I also looked similar questions, but I wasn't able to find the reason why my program crashes.
These are the private variables for the class SetT
forward_list<T>** buckets; // An array of forward_list's
// (ie, each index is a forward_list pointer)
int numBuckets;
int getHashIndex(const T& elem);
int numElems;
// Iterator variables
int currBucket; // what bucket is the iterator on?
mutable typename forward_list<T>::iterator bucketIter; // the iterator of the current bucket
This is the code for Add:
template<class T>
bool SetT<T>::Add(T elem)
{
// If the set already contains elem, do nothing
if (Contains(elem)) {
return false;
}
// Get the bucket index and add the element to the bucket.
currBucket = getHashIndex(elem);
buckets[currBucket]->push_front(elem);
numElems++;
return true;
// Extra credit: If the load factor becomes too large, change the number of buckets and rehash.
}
The hashing function was given by our professor, and he told us not to touch it.
This is the code for Contains:
template<class T>
bool SetT<T>::Contains(T elem)
{
// Use hash function to find the bucket, then check
// to see if elem is in the bucket.
currBucket = getHashIndex(elem);
for (bucketIter = buckets[currBucket]->begin(); bucketIter != buckets[currBucket]->end(); ++bucketIter) {
if (elem == *bucketIter) {
return true;
}
}
return false;
}
And this is the code for the operators
template<class T>
SetT<T> SetT<T>::operator*(SetT& other)
{
SetT<T> result;
// Your code here
// This function should return the Intersection between "this" and otherSet.
// It should NOT change "this" or otherSet
for (int i = 0; i < numBuckets; i++) {
for (bucketIter = buckets[i]->begin(); bucketIter != buckets[i]->end(); ++bucketIter) {
T value = *bucketIter;
if (Contains(value) && other.Contains(value)) {
result.Add(value);
}
}
}
return result;
}
template<class T>
SetT<T> SetT<T>::operator=(const SetT& other)
{
if (other.numElems == 0) {
return SetT<T>();
}
else {
return other;
}
}
Does anyone know what is causing this error?
Thanks.
Edit: This is the professor's hash function
template<class T>
int SetT<T>::getHashIndex(const T& key)
{
// This is done... No touching!
unordered_map<int, T> mapper;
typename unordered_map<int, T>::hasher hashFunction = mapper.hash_function();
return static_cast<int>(hashFunction(key) % numBuckets);
}
I'm just trying to get C++ down and to do that, I gotta make my own libraries and whatnot. So I'm trying to get the beginnings of my own List template class, exactly like the List class in the JDK. So I've got the template and stuff down, I just wanna know how I would make it so that I could loop through the contents of a list object. This way I can print out the contents of said object. I don't exactly know where to start.
#pragma once
template<typename T> class List {
public:
List() : _size(0), _elements(nullptr) {}
~List() {
if (_elements != nullptr) {
delete[] _elements;
}
}
inline int size() { return _size; }
inline void add(T element) {
_size++;
T* buffer = new T[_size];
if (_elements != nullptr) {
memcpy(buffer, _elements, sizeof(T) * (_size - 1));
delete[] _elements;
}
buffer[_size - 1] = element;
_elements = buffer;
}
inline void remove(T element) {
_size--;
T* buffer = new T[_size];
if (_elements != nullptr) {
memcpy(buffer, _elements, sizeof(T) * _size);
delete[] _elements;
}
else {
assert(false);
}
_elements = buffer;
}
inline T* getElements() {
return _elements;
}
private:
int _size;
T* _elements;
};
And this is my main Cpp file
#include <cstdio>
#include <string>
#include "List.h"
using namespace std;
int main( int argc, char ** argv )
{
string str = "This is a test!";
List<char> list = breakString(str);
for (char c : list.getElements()) {
}
getchar();
return 0;
}
List<char> breakString(string str) {
List<char> list;
for (char c : str) {
list.add(c);
}
return list;
}
So what I'm trying to figure out is in that for loop, I'm used to it being an enhanced for loop like in Java, and is that the same here in C++? If so, how would I make this object iterable?
I figured I would get a more accurate answer to my question if I asked directly.
The guidelines for validating the Range-based for can be found on http://en.cppreference.com/w/cpp/language/range-for
If range_expression is an expression of a class type C that has a member named begin and/or a member named end (regardless of the type or accessibility of such member), then begin_expr is __range.begin() and end_expr is __range.end();
In short, since your data is in a raw array, you should add these public methods to you class List<T>
T* begin() { return _elements;}
T* end() { return _elements + _size;}
And then you can invoke the Range-based for on the object directly:
for (char c : list)
But you have other issues in your code. One of them (not sure it's the only one) is that breakString returns an object, but your class is not trivial and it does not define any copy or move constructors.
This answer adresses the "main" question as to how the enable the Range-based for for your class. It just needs two methods begin() and end() that return something that looks like an iterator (could be an actual iterator or a pointer to a contiguous memory chunk")
You can test the suggested modifications without using breakString, like this:
int main( int argc, char ** argv )
{
std::string str = "This is a test!";
List<char> list;
for (char c : "abcdef") { list.add(c); }
for (char c : list) { std::cout << c << "\n"; }
}
And to make it "fully iterable" define you can define a nested class called ierator..
I have a class idx_aware that goes into a container container, which wraps around a std::vector. When the class is added to container, container sets a pointer to itself in idx_aware, as well as the index of idx_aware in its internal memory storage.
The index is not going to change until the container is destroyed or idx_aware is removed; idx_aware needs to know about its container and its index, because it has some methods that require both to work.
Now this introduces the following problem: when I get a non-const reference to an idx_aware class contained in container, I could assign to it another idx_aware class, which could have a different index. The intention would be assigning all the fields and keeping the index as it is.
#include <vector>
#include <limits>
#include <iostream>
class container;
// Stores a std::size_t field, which can be set only by subclasses.
class with_idx {
std::size_t _i;
public:
with_idx() : _i(std::numeric_limits<std::size_t>::max()) {}
operator std::size_t() const { return _i; }
protected:
void set_idx(std::size_t i) { _i = i; }
};
// Knows its index and its container
class idx_aware : public with_idx {
container const *_container;
int _some_field1;
float _some_field2;
public:
void foo() {
// Do stuff using _container and _i
}
private:
friend class container;
};
// Wraps around a std::vector
class container {
std::vector<idx_aware> _data;
public:
idx_aware &operator[](std::size_t idx) {
// Need non-const access to call foo
return _data[idx];
}
idx_aware const &operator[](std::size_t idx) const {
return _data[idx];
}
std::size_t add(idx_aware const &item) {
// Here it could potentially reuse a freed position
std::size_t free_slot = _data.size();
// Ensure _data is big enough to contain free_slot
if (_data.size() <= free_slot) {
_data.resize(free_slot + 1);
}
// Assign
_data[free_slot] = item;
_data[free_slot].set_idx(free_slot);
_data[free_slot]._container = this;
return free_slot;
}
};
int main() {
container c;
idx_aware an_item;
std::size_t i = c.add(an_item);
std::cout << c[i] << std::endl; // Prints 0
idx_aware another_item; // Created from somewhere else
// I want to set all the data in idx_aware, but the
// index should stay the same!
c[i] = another_item;
std::cout << c[i] << std::endl; // Prints numeric_limits<size_t>::max()
// Now container[i] is broken because it doesn't know anymore its index.
return 0;
}
One possible workaround would be to change with_idx in such a way that when set_idx is called, a flag is set that prevents assignment and copy operator to overwrite the _i property, like this:
class with_idx {
std::size_t _i;
bool _readonly;
public:
with_idx() : _i(std::numeric_limits<std::size_t>::max()), _readonly(false) {}
with_idx(with_idx const &other) : _i(other._i), _readonly(false) {}
with_idx &operator=(with_idx const &other) {
if (!_readonly) {
_i = other._i;
}
return *this;
}
operator std::size_t() const { return _i; }
protected:
void set_idx(std::size_t i) {
_i = i;
if (i != std::numeric_limits<std::size_t>::max()) {
// This has been set by someone with the right to do so,
// prevent overwriting
_readonly = true;
} else {
// Removed from the container, allow overwriting
_readonly = false;
}
}
};
This would have the consequence of returning, after assignment, a reference to an idx_aware class with unchanged index.
idx_aware ¬_in_container1 = /* ... */;
idx_aware ¬_in_container2 = /* ... */;
idx_aware &in_container = /* ... */;
not_in_container1 = in_container = not_in_container2;
// std::size_t(not_in_container_1) != std::size_t(not_in_container_2)
Is there a design pattern that can model this situation in a better way? My searches were not successful.
Are there other unwanted consequences of overriding the assignment operator in this way? The limitation I pointed out in the previous example does not look too "bad".
Is there an easier solution? I thought about writing some proxy object to replace the idx_aware & return type of operator[].
Experience tells that when C++ does not do what you intend, you are likely to be misusing OOP...
Robert's comment suggested me this solution.
Why would the contained object know about its container? To be able to perform actions such as foo and provide shorthand methods that otherwise would require to have access to the container.
Let's take this functionality away from the contained object; the contained object is just data payload. Instead, let's make operator[] return not the contained object, but some sort of iterator, a wrapper around the contained object, which knows the container and the index, and once dereferenced returns the actual contained object.
class was_idx_aware {
int _some_field1;
float _some_field2;
};
class container {
std::vector<idx_aware> _data;
public:
class idx_aware_wrapper {
container const *_container;
std::size_t _idx;
public:
idx_aware_wrapper(container const &c, std::size_t i)
: _container(&c)
, _idx(i)
{}
was_idx_aware const &operator*() const {
return _container->_data[_idx];
}
was_idx_aware &operator*() {
return _container->_data[_idx];
}
void foo() {
// Do stuff using _container and _idx.
}
};
idx_aware_wrapper operator[](std::size_t i) {
return idx_aware_wrapper(*this, i);
}
/* .... */
};
This allows quick access to any data in was_idx_aware, and the wrapper class can be augmented with all the methods that require interaction with the container. No need to store and keep indices up to date or override assignment operators.
As part of an assignment for a data structures class, I am trying to get this over a decade-old code to actually work. The code is found here: http://www.brpreiss.com/books/opus4/
(And to all of the users here who are horrified at such bad design, take heart - this is a homework assignment where the goal is ostensibly to get someone else's code to work. I am not advocating its use.)
Here, the author defined the class Stack and its associated Iterator:
#ifndef STACK_H
#define STACK_H
#include "linkList.h"
#include "container.h"
class Stack : public virtual Container
{
public:
virtual Object& Top () const = 0;
virtual void Push (Object&) = 0;
virtual Object& Pop () = 0;
};
class StackAsLinkedList : public Stack
{
LinkedList<Object*> list;
class Iter;
public:
StackAsLinkedList () : list() {}
~StackAsLinkedList() { Purge(); }
//
// Push, Pop and Top
//
void Push(Object& object);
Object& Pop() override;
Object& Top() const override;
int CompareTo(Object const& obj) const;
//
// purge elements from, and accept elements onto, the list
//
void Purge();
void Accept (Visitor&) const;
friend class Iter;
};
class StackAsLinkedList::Iter : public Iterator
{
StackAsLinkedList const& stack;
ListElement<Object*> const* position;
public:
Iter (StackAsLinkedList const& _stack) : stack(_stack) { Reset(); }
//
// determine whether iterator is pointing at null
//
bool IsDone() const { return position == 0; }
//
// overloaded dereference and increment operator
//
Object& operator*() const;
void operator++();
void Reset() { position = stack.list.Head(); }
};
#endif
I am not sure what the objective is here, because trying to instantiate a StackAsLinkedList::Iter will predictably give an error because it is private. Furthermore, the author doesn't use the iterator he just implemented for stack in the below example, which instead uses the iterator defined in the parent class of Stack called Container to traverse the stack and print the values:
StackAsLinkedList stack;
Iter& i = stack.NewIterator();
stack.Push(*new Int(1) ); //type "Int" is a Wrapper for primitive "int"
stack.Push(*new Int(2) );
...
while ( ! outIter.IsDone() )
{
cout << *outIter << endl;
++outIter;
}
...
But when he creates stack.NewIterator(), a look at the method call in Container shows:
virtual Iterator& NewIterator () const { return *new NullIterator (); }
So the conditional in the while statement will always fail and thus the body will never execute.
This leads me to believe that I should be implementing another NewIterator method for Stack, but I am not sure what the return value should be ( *new StackAsLinkedList::Iter(_stack) ?).
Any ideas?
Adding the following method in StackAsLinkedList seemed to clear up the problem:
Iterator& StackAsLinkedList::NewIterator() const
{
return *new Iter(*this);
}
Also, the order of assignment in main() was also an issue. This seemed to correct it:
StackAsLinkedList stack;
stack.Push(*new Int(1) ); //type "Int" is a Wrapper for primitive "int"
stack.Push(*new Int(2) );
...
Iter& i = stack.NewIterator();
while ( ! outIter.IsDone() )
{
cout << *outIter << endl;
++outIter;
}
I realize that this solution is not ideal - ideally I should refactor or better yet just start over (or just use STL). But as I said above, the goal was to just get this stuff to compile and work within a limited time-frame. So to echo what others have said: please don't use this code!