c++ linkedlist list operator[] - c++

I am trying to implement linkedlist, and i have some problem with operator[]
template <class T>
T& L1List<T>::at(int i){
L1Item<T> * pRet = this->_pHead;
int idx = 0;
while(pRet){
if(i != idx){
pRet = pRet->pNext;
idx++;
}else return (pRet->data);
}
}
template <class T>
T& L1List<T>::operator[](int i){
return at(i);
}
and when i compile it, it runs with list->at(i), but list[i].
int a = list[i]; the error is that "cannot convert L1List'<'int> to ‘int’ in initialization"

If list->at(i) works, it means that list is a pointer, not an object. Hence, list[i] evaluates to an object. That's why int a = list[i]; does not work, which also explains the error message. You cannot use a L1List<int> to initialize an object of type int.
You need to use:
int a = (*list)[i];
or make it really complicated and use:
int a = list->operator[](i);

Related

operator= bout side one by value second by refrence?

the Q is how to this kind of operator=
that it will work on:
int t = v[3]; // her i return by Value
v[3] = 8 ; // her i need to return by refrence (pointer to V[3] add')
will V is a Vector class (template class in my case)
template <class T>
T& Vector<T>::operator[](const int Index) const
{
if(Index > -1 && Index < this->Size)
{
return &this->Array[Index];
}
else
{
cerr <<"VECTOR_INVALID_INDEX"<<endl;
return NULL;
}
};
There are several errors in this example. this is already a pointer. Doing &this is almost certainly not what you meant to do here. The other problem you are having is that you are returning a reference to T but this is const in this context. this->Array[Index] is const T which cannot bind to T&. Add a const and return const T& instead. Thirdly, this->Size is not calling the method Size, you forgot parentheses. The fourth problem is a reference binding to NULL. You will have to decide on another approach. The usual way to indicate that an operation cannot be completed is to throw an exception. std::vector::at throws std::out_of_range from header stdexcept.
template <class T>
const T& Vector<T>::operator[](const int Index) const
//^^^ add const here
{
if (Index > -1 && Index < this->Size())
// Add parentheses ^^
{
return this->Array[Index];
// ^ No need for &
}
else
{
throw std::out_of_range("VECTOR_INVALID_INDEX");
}
};
You will probably want to add a non-const version as well, since this will fail for the example v[3] = 8;. Define this method as well with the same body :
T& Vector<T>::operator[](const int Index);

C: var was not declared in this scope

I am attempting to get my array wrapper class to compile, but I'm new to c++. I keep getting a series of relating to the last function:
Line 81
Invalid Use of template-name 'warray' without an arugment list
Line 81
ISO C++ forbids declaration of 'parameter' with not type
line 81
error expected ',' or '...' before < town
line 83
rhs was not declared in this scope
and finally, line 86
rhs was not declared in this scope
This function is so confusing, and I think I implemented it all correct.
IDK! Please help!
#ifndef WARRAY
#define WARRAY
#include <iostream>
#include <stdexcept>
template <typename T>
class warray {
private:
unsigned int theSize;
T* theData;
public:
//will default to a size of 10 - bump to 10 if below
warray(unsigned int size = 10){
if(size < 10){
size = 10;
}
theSize = size;
theData = new T[theSize];
}
//copy
warray(const warray &rhs):theSize(rhs.theSize){
theData = new T[theSize];
//use assignment*this = rhs;
*this = rhs;
}
//assignment
warray & operator=(const warray &rhs){
//only resize array if lhs < than rhs//this also remedies
if(theSize < rhs.theSize){
delete [] theData;
theData = new T[rhs.theSize];
}
theSize = rhs.theSize;
for(unsigned int i = 0; i < theSize; ++i){
(*this);
}
return *this;
}
//destrctor
~warray(){
delete [] theData;
}
//operator+ will concatenate two arrays should be const
warray operator+(const warray &rhs) const{
warray toRet(theSize + rhs.size);
for(unsigned int i = 0; i < theSize; ++i){
toRet[i] = (*this)[i];
}
for(unsigned int i = 0; i < theSize; ++i){
toRet[i+theSize] = rhs[i];
}
return warray();
}
//operator[unsigned T index]
//will index and allow access to requested element
// - two versions, const and non-const
T operator[](unsigned int index) const{
if(index >= theSize){
throw std::out_of_range ("in operator [] ");
}
return theData[theSize];
}
//size
unsigned int size() const{
return theSize;
}
};
std::ostream &operator<< (std::ostream &os, const warray&<T> rhs){
os << "[ ";
for(unsigned i = 0; i < rhs.size()-1; ++i){
os << rhs[i] << " , ";
}
os << rhs[rhs.size() - 1] << " ]";
return os;
}
#endif
This line:
T *theData [theSize];
attempts to declare an array of pointers of size theSize, but theSize is not a constant and is not known at compile time. You also don't want an array of pointers to T, you want a pointer to an array of T.
change it to
T *theData;
There are other problems with your code. e.g. your << operator needs to be a template and I have no idea what (*this) is trying to achieve.
Note: I am assuming you are doing this for learning purposes and can't simply use a vector.
Edit: The "Invalid Use of template-name 'warray' without an argument list" error is caused by the << operator not having template<typename T> in front of it. It needs this to make it a templated function.
You have marked this as C++.
I recommend you change from:
class warray {
private:
unsigned int theSize;
T* theData;
And perhaps try:
class warray {
private:
std::vector<T> theData;
What you call "theSize" is now available as theData.size().
To append values of T, use push_back().
If you desire, you can allocate a start size using theData.reserve(size), but not necessary.
Remove
delete [] theData;
because you no longer 'new'd it in the ctor.
The vector's dtor will be called automagically when your warray instance is dtor'd.
Can't define theData this way:
T *theData[theSize];
defining the size of a static array with a variable is non-standard. Some compilers allow it, some don't. Best practice is not to do it so you don't get tripped up. As it is, the Size has no defined value at that point so even if your compiler did that trick, there is a ton of ka-boom potential.
Fortunately, based on the rest of the code, you don't need to. You keep defining the size of the array yourself, so:
T *theData;
Should do you just fine.

No such operator "[]" matches these operands

I am trying to make a program that demonstrates use of templates and overloaded operators for my CS class. Here is relevant code:
main:
ArrayTemplate<int> number(0);
number[0] = 1;
number[1] = 2;
number[2] = 3;
ArrayTemplate<string> word("na");
word[0] = "One";
word[1] = "Two";
word[2] = "Three";
header:
template<class T>
T& operator [](const int index)
{
if(index >= 0 && index < ARRAY_MAX_SIZE)
return items[index];
else
{
cerr << "INDEX OUT OF BOUNDS!!!";
exit(1);
}
}
The problem is that when I try to use my overloaded subscript operator I get the error message shown in title: "No such operator "[]" matches these operands" Im not exactly sure why. It does it for both my integer array and my string array. Any help is appreciated.
You really need to show the full definition of ArrayTemplate.
This is how you probably want it to look:
template<class T>
class ArrayTemplate {
public:
// ...
T& operator [](const int index)
{
if(index >= 0 && index < ARRAY_MAX_SIZE)
return items[index];
else
{
cerr << "INDEX OUT OF BOUNDS!!!";
exit(1);
}
}
// ...
};
Note that operator[] isn't templated; only the class is.
With your current code you would have to do it like this:
number<int>[0] = 1;
number<int>[1] = 2;
number<int>[2] = 3;
Which obviously goes against your intention.
template<class T>
T& operator [](const int index)
This declaration would be called e.g. as object.operator[] < type >( 5 ). Note that type needs to be provided as a template argument. Because there's no way to supply such an argument in an expression using [], the operator overload doesn't work.
Probably you don't want the template< class T > at all. Just get rid of it:
T& operator [](const int index)
If you define the function outside the class {} scope, then it would look like this:
template<class T>
T& ArrayTemplate<T>::operator [](const int index)
In this case, the template<class T> line re-introduces the parameter in order to get back into the class template.

Template & memory-allocation

#include <iostream>
template<class T> T CreateArray(T a, int n)
{
a = new T [n]; // mistake: double* = double**
return a;
}
int main()
{
double* a;
int n = 5;
a = CreateArray(a,n);
return 0;
}
can I allocate memory using a template and new? And what my mistake?
Your code has some wrong things. First, you can do something like what you're trying to do, but you should write something like this:
template<class T> T* CreateArray(int n)
{
T* a = new T [n];
return a;
}
int main()
{
double* a;
int n = 5;
a = CreateArray<double>(n);
return 0;
}
Note that you don't have to pass the a array (it will be copied inside CreateArray, and its changes won't be visible inside main). Note also that you define the template to returning a pointer T*, that is what main() a is expecting.
So others have explained why your code doesn’t work and how it can be improved.
Now I’ll show how you can still get the following code to compile – and to work properly:
double* a = CreateArray(5);
int* b = CreateArray(7);
The problem, as already mentioned, is that C++ does not infer template arguments from return types alone.
You can circumvent this limitation by making the above function return a simple proxy object. The proxy object has a single operation: an (implicit) conversion to T*. This is where the actual allocation happens.
The CreateArray function is therefore very simple (and not a template):
CreateArrayProxy CreateArray(std::size_t num_elements) {
return CreateArrayProxy(num_elements);
}
As for the proxy:
struct CreateArrayProxy {
std::size_t num_elements;
CreateArrayProxy(std::size_t num_elements) : num_elements(num_elements) { }
template <typename T>
operator T*() const {
return new T[num_elements];
}
};
Easy as π.
Now, should you use this code? No, probably not. It offers no real advantage over direct allocation. But it’s a useful idiom to know.
You want to accept a pointer to the type you want to allocate:
template<class T> T* CreateArray(T* a, int n)
{
a = new T [n];
return a;
}
This should do the trick.
I prefer to keep empty pointers value NULL.
#include <iostream>
template<class T> bool CreateArray(T * &a, int n)
{
if ( a != 0 )
return false;
a = new T [n];
return true;
}
int main()
{
double* a = 0;
int n = 5;
CreateArray(a,n);
return 0;
}
vector could be a good solution, too. I think it is better one, because you won't make memory leak(s).
#include <vector>
int main()
{
std::vector<double> a;
int n = 5;
a.resize(n);
return 0;
}

C++ Operator overloading - 'recreating the Vector'

I am currently in a collage second level programing course... We are working on operator overloading... to do this we are to rebuild the vector class...
I was building the class and found that most of it is based on the [] operator. When I was trying to implement the + operator I run into a weird error that my professor has not seen before (apparently since the class switched IDE's from MinGW to VS express...) (I am using Visual Studio Express 2008 C++ edition...)
Vector.h
#include <string>
#include <iostream>
using namespace std;
#ifndef _VECTOR_H
#define _VECTOR_H
const int DEFAULT_VECTOR_SIZE = 5;
class Vector
{
private:
int * data;
int size;
int comp;
public:
inline Vector (int Comp = 5,int Size = 0)
: comp(Comp), size(Size) { if (comp > 0) { data = new int [comp]; }
else { data = new int [DEFAULT_VECTOR_SIZE];
comp = DEFAULT_VECTOR_SIZE; }
}
int size_ () const { return size; }
int comp_ () const { return comp; }
bool push_back (int);
bool push_front (int);
void expand ();
void expand (int);
void clear ();
const string at (int);
int& operator[ ](int);
int& operator[ ](int) const;
Vector& operator+ (Vector&);
Vector& operator- (const Vector&);
bool operator== (const Vector&);
bool operator!= (const Vector&);
~Vector() { delete [] data; }
};
ostream& operator<< (ostream&, const Vector&);
#endif
Vector.cpp
#include <iostream>
#include <string>
#include "Vector.h"
using namespace std;
const string Vector::at(int i) {
this[i];
}
void Vector::expand() {
expand(size);
}
void Vector::expand(int n ) {
int * newdata = new int [comp * 2];
if (*data != NULL) {
for (int i = 0; i <= (comp); i++) {
newdata[i] = data[i];
}
newdata -= comp;
comp += n;
data = newdata;
delete newdata;
}
else if ( *data == NULL || comp == 0) {
data = new int [DEFAULT_VECTOR_SIZE];
comp = DEFAULT_VECTOR_SIZE;
size = 0;
}
}
bool Vector::push_back(int n) {
if (comp = 0) { expand(); }
for (int k = 0; k != 2; k++) {
if ( size != comp ){
data[size] = n;
size++;
return true;
}
else {
expand();
}
}
return false;
}
void Vector::clear() {
delete [] data;
comp = 0;
size = 0;
}
int& Vector::operator[] (int place) { return (data[place]); }
int& Vector::operator[] (int place) const { return (data[place]); }
Vector& Vector::operator+ (Vector& n) {
int temp_int = 0;
if (size > n.size_() || size == n.size_()) { temp_int = size; }
else if (size < n.size_()) { temp_int = n.size_(); }
Vector newone(temp_int);
int temp_2_int = 0;
for ( int j = 0; j <= temp_int &&
j <= n.size_() &&
j <= size;
j++) {
temp_2_int = n[j] + data[j];
newone[j] = temp_2_int;
}
////////////////////////////////////////////////////////////
return newone;
////////////////////////////////////////////////////////////
}
ostream& operator<< (ostream& out, const Vector& n) {
for (int i = 0; i <= n.size_(); i++) {
////////////////////////////////////////////////////////////
out << n[i] << " ";
////////////////////////////////////////////////////////////
}
return out;
}
Errors:
out << n[i] << " "; error C2678:
binary '[' : no operator found which
takes a left-hand operand of type
'const Vector' (or there is no
acceptable conversion)
return newone;
error C2106: '=' : left
operand must be l-value
As stated above, I am a student going into Computer Science as my selected major I would appreciate tips, pointers, and better ways to do stuff :D
This:
int operator[ ](int);
is a non-const member function. It means that it cannot be called on a const Vector.
Usually, the subscript operator is implemented such that it returns a reference (if you return a value, like you are doing, you can't use it as an lvalue, e.g. you can't do newone[j] = temp_2_int; like you have in your code):
int& operator[](int);
In order to be able to call it on a const object, you should also provide a const version of the member function:
const int& operator[](int) const;
Since you ask for "tips, pointers, and better ways to do stuff:"
You cannot name your include guard _VECTOR_H. Names beginning with an underscore followed by a capital letter are reserved for the implementation. There are a lot of rules about underscores.
You should never use using namespace std in a header.
Your operator+ should take a const Vector& since it is not going to modify its argument.
Your at should return an int and should match the semantics of the C++ standard library containers (i.e., it should throw an exception if i is out of bounds. You need to use (*this)[i] to call your overloaded operator[].
You need to learn what the * operator does. In several places you've confused pointers and the objects to which they point.
Watch out for confusing = with == (e.g. in if (comp = 0)). The compiler will warn you about this. Don't ignore warnings.
Your logic will be much simpler if you guarantee that data is never NULL.
Can't fit this into a comment on Neil's answer, so I'm gonna have to go into more detail here.
Regarding your expand() function. It looks like this function's job is to expand the internal storage, which has comp elements, by n elements, while maintaining the size of the Vector. So let's walk through what you have.
void Vector::expand(int n) {
int * newdata = new int [comp * 2];
Okay, you just created a new array that is twice as big as the old one. Error: Why doesn't the new size have anything to do with n?
if (*data != NULL) {
Error: *data is the first int element in your array. It's not a pointer. Why is it being compared to NULL?
Concept Error: Even if you said if (data != NULL), which could be a test to see if there is an array at all, at what point in time is data ever set to NULL? new [] doesn't return NULL if it's out of memory; it throws an exception.
for (int i = 0; i <= (comp); i++) {
newdata[i] = data[i];
}
Warning: You're copying the whole array, but only the first size elements are valid. The loop could just run up to size and you'd be fine.
newdata -= comp;
Error: Bad pointer math. newdata is set to a pointer to who knows where (comp ints back from the start of newdata?!), and almost certainly a pointer that will corrupt memory if given to delete [].
comp += n;
This is fine, for what it is.
data = newdata;
delete newdata;
}
Error: You stored a pointer and then immediately deleted its memory, making it an invalid pointer.
else if ( *data == NULL || comp == 0) {
data = new int [DEFAULT_VECTOR_SIZE];
comp = DEFAULT_VECTOR_SIZE;
size = 0;
}
}
Error: This should be in your constructor, not here. Again, nothing ever sets data to NULL, and *data is an int, not a pointer.
What this function should do:
create a new array of comp + n elements
copy size elements from the old array to the new one
delete the old array
set data to point to the new array
Good luck.
Besides of what others already wrote about your operator[]():
Your operator+() takes the right-hand side per non-const reference - as if it would attempt to change it. However, with A+B everyone would expect B to remain unchanged.
Further, I would implement all binary operators treating their operands equally (i.e., not changing either of them) as non-member functions. As member functions the left-hand side (this) could be treated differently. (For example, it could be subjected to overwritten versions in derived classes.)
Then, IME it's always good to base operator+() on operator+=(). operator+=() does not treat its operands equally (it changes its left one), so it's best done as a member function. Once this is done, implementing operator+() on top of it is a piece of cake.
Finally, operator+() should never, never ever return a reference to an object. When you say A+B you expect this to return a new object, not to change some existing object and return a reference to that.
There are so many errors in your code that it is hard to know where to start. Here's one:
delete [] data;
*data = *newdata;
You delete a pointer and then immediately dereference it.
And:
const string Vector::at(int i) {
this[i];
}
This is (I think) a vector of ints. why is this returning a string? And applying the [] operator to this does not call your operator[] overload - it treats this as an array, which it isn't.
You need to provide two versions of your operator[]. For accessing:
T operator[](std::size_t idx)const;
For writing to the element:
T& operator[](std::size_t idx);
In both of the above, replace T with the type of the elements. The reason you have this problem is that only functions that are marked "const" may be invoked on an object declared to be "const". Marking all non-mutating functions as "const" is definitely something you should do and is called "const-correctness". Since returning a reference to an element (necessary for writing) allows the underlying object to be mutated, that version of the function cannot be made "const". Therefore, a read-only "const" overload is needed.
You may also be interested in reading:
Const Correctness from the C++ FAQ Lite
Const Correctness in C++
int Vector::operator[] (int place) { return (data[place]); }
This should be
int Vector::operator[] (int place) const { return (data[place]); }
so that you will be able to do the [] operation on const vectors. The const after the function declaration means that the class instance (this) is treated as const Vector, meaning you won't be able to modify normal attributes. Or in other words: A method that only has read access to attributes.