c++ overload [] operator - c++

I am trying to overload the subscript operator [] in my class which uses a linked list to create a map. This and several variations, like adding const, is what I have tried.
header
int& operator[](std::string key);
and then defining the overload in a seperate file
int& mapLL::operator[](std::string key){
int val = this->get(key);
return val;
}
this is the error I don't know how to fix
main.cpp: In function ‘int main()’:
main.cpp:38:24: error: invalid types ‘mapLL*[const char [4]]’ for array subscript
int a = list3["ghi"];
^
mapLL.cpp: In member function ‘int& mapLL::operator[](std::string)’:
mapLL.cpp:110:9: warning: reference to local variable ‘val’ returned [-Wreturn-local-addr]
int val = this->get(key);
^
Then in the main file I am trying this
mapLL *list3 = new mapLL();
list3->set("abc",1);
list3->set("def",2);
list3->set("ghi",3);
list3->set("jkl",1);
list3->toString();
cout << list3->get("ghi") << endl;
int a = list3["ghi"];
cout << a << endl;
delete list3;
get function
int mapLL::get(std::string key){
bool found = false;
node *me = (node *) first;
if(is_empty()){
return -2;
}
while(!found){
if (me->getKey() == key){
return me->getValue();
}else{
if (me->getNext() == 0){
return -1;
}else{
me = (node *) me->getNext();
}
}
}
}

int& mapLL::operator[](std::string key){
int val = this->get(key);
return val;
}
you are returning a reference to a local variable, val.
what you actually need to do is to find the element in you linked list and return it as is, no assignment to local variables in between.
Plus, list3 is a pointer, unfortunatly, you need to dereference it before using [] operator :
(*list3)["ghi"];
all have being said + looking at your profile, I get that you come from a Java background. my advice - understand what is the difference between stack allocation and heap allocation. this is the very basic of the language. you need to use dynamically allocated objects (=using new) very rarely.
although Java hides away allocation details, this is maybe the one of the most important subjects in C++. not everything has to be a pointer. your starting point is stack allocated objects. move from there to dynamic /static allocation if it does not line with your needs.

I recommend to refrain from using raw pointers and dynamic allocation. Your issue stems from incorrect use of pointers.
Use direct declarations:
mapLL list3;
list3.set("abc",1);
list3.set("def",2);
list3.set("ghi",3);
list3.set("jkl",1);
list3.toString();
cout << list3.get("ghi") << endl;
int a = list3["ghi"];
cout << a << endl;

Related

why is the stackdisplay function not working

this is a simple program for using a stack. it basically does all the stack operations, when I run it the programming is not working for some reason and I can't figure out the reason why. also, is there any way I can improve this current code?
this is the program code here
//
#include <iostream>
using namespace std;
struct stack {
int top = -1;
int size;
int* p;
} *stack;
struct stack* createStack(int size)
{
struct stack st;
st.p = new int[size];
st.size = size;
struct stack* stackPointer = &st;
return stackPointer;
}
void push(struct stack* st, int el) {
if (st->top == (st->size) - 1) {
cout << "this operation cannot be done as the size is full :(" << endl;
}
else
{
st->top = (st->top)++;
st->p[st->top] = el;
}
}
void pop(struct stack* st) {
if (st->top == -1)
cout << "stack is already empty" << endl;
else
st->p[st->top] = NULL;
}
void displayStack(struct stack* st) {
for (int i = 0; i <= st->top; i++) {
cout << st->p[i] << endl;
}
}
int main()
{
struct stack* st = createStack(5);
push(st, 1);
push(st, 2);
push(st, 3);
push(st, 4);
displayStack(st);
pop(st);
displayStack(st);
}
There are a few problems with your code. First, as others have said, you're just doing C code without cout. Instead, you might want stack to look like this:
struct stack {
stack(int sz);
void push(int value);
int pop();
int top = -1;
int size = 0;
int * p = nullptr;
};
std::ostream & operator<<(stack &stack) {
for (int i = 0; i <= stack->top; i++) {
cout << stack->p[i] << endl;
}
}
stack::stack(int sz)
: size(sz), p(new int[size])
{
}
void push(int value) {
if (top == (size) - 1) {
cout << "this operation cannot be done as the size is full :(" << endl;
}
else {
p[++top] = el;
}
}
int pop() {
return top < 0 ? INT_MIN : p[top--];
}
int main() {
stack st(5);
st.push(1);
st.push(2);
st.push(3);
st.push(4);
cout << "First dump: " << st << endl;
st.pop();
cout << "Second dump: " << st << endl;
}
At first: You tagged C++, but your code is C – apart from not providing void to main, outputting to std::cout and using namespace std – the latter you shouldn't do anyway!
createStack function should be a constructor instead, push and pop should be member functions and you should prevent access to the internal data by making it private. Typically, one would rather use a class than a struct (structs usually are used for POD types). That would look like:
class Stack
{
// default accessibility for class is private, so need to switch to public first
public:
Stack(size_t capacity)
: m_capacity(capacity), m_size(0), m_data(new int[capacity])
{ }
bool push(int value);
bool pop();
int top();
// now private section:
private:
size_t m_capacity;
size_t m_size;
//int* m_data;
// use of a smart pointer avoids necessity to care for memory management manually:
std::unique_ptr<int[]> m_data;
};
Sure, that looks pretty different now. But that's the C++ way. If you don't get along with you might want to peek in a good C++ book.
Some additional changes:
I renamed size to capacity, and top to size. Correct data type for specifying object or array sizes is std::size_t (or just size_t), you need to #include <cstddef> for. Note, though, that this type is unsigned (negative sizes are meaningless anyway).
Old top/new size has different semantics, not indexing the last element, but holding the number of elements – or index to one past the last element. This is rather typical semantics in C++ – and actually C as well.
The m_ prefix signals the variables being members of a class, it helps distinguishing class members from local variables. Such a convention is not uncommon, but no necessity. Decide you yourself if you want to follow or not...
I added a top function returning the last element on the stack. Note that the data and size members are private, so they cannot be accessed from outside the class, thus a user couldn't retrieve the top element without the function.
I changed the return types from void to bool – it is a pretty questionable idea to do any output from within a general purpose class. Users of it might want to provide different output, e.g. in another language, and you now are spoiling their programme. In other words: You limit reusability. So let's just return a success indicator and leave the output to the user (you personally would do so within main then).
Of course implementation needs to be changed a little bit, too. You might add the function bodies directly within the class definition (drop the semicolon then), usually you define the class in a header (stack.h or stack.hpp), but the member functions in a separate source file (stack.cpp). The latter would then contain:
#include "stack.h" // should always be the very first include:
// implicit check, if the header is self-contained, i.e.
// includes all headers it needs for the class definition
bool stack::push(int value)
// ^^ scope resolution: identifies the push function of class stack
{
if(m_size == m_capacity)
{
return false;
}
m_data[m_size++] = value;
return true;
}
bool stack::pop()
{
if(m_size == 0)
{
return false;
}
--m_size;
// you don't need to assign another value like 0
// it would be overwritten with next push anyway
//
// note that NULL would have been wrong anyway, that's for pointers!
// apart from, you should prefer C++ KEYWORDS over obsolete C MACROS,
// i.e. prefer nullptr over NULL
//
// note, too, that you did NOT reduce top on popping in your version
// should have caused outputting 1234 twice in your test code instead
// of 1234 and 123 – which I assume you meant by 'not working'
// – please get used to more precise error descriptions, by the way!
return true;
}
int top()
{
return m_data[m_size - 1];
}
Well, top is a pretty basic implementation, it relies on undefined behaviour if the stack is empty (i.e. it is the responsibility of the user to check size first!). Alternatively you could:
check the size yourself and throw an exception if the stack is empty
change the return type to bool and have a reference argument to provide the top value to (bool top(int& value);) – as being a reference, you indeed can do assignments to.
main would contain code like this one:
Stack s;
s.push(1);
// ^ call class member function; for pointers use ->
s.push(2);
std::cout << s.top();
s.pop();
Finally outputting the entire stack:
Have you noticed that you can write std::cout << 7 << someVariable << std::endl;? What if you could do the same with your stack?
No problem:
class Stack
{
public:
// see above
private:
// need to declare a FRIEND so that the function/operator has access to
// the private class members
friend std::ostream& operator<<(std::ostream& s, Stack const& s);
// private members, see above
};
std::ostream& operator<<(std::ostream& s, Stack const& s)
{
// now do the output to s just as the original displayStack did to std::cout
// but consider the changed semantics of top/size
return s;
}
That's it:
Stack s;
std::cout << s << std::endl; // now fine
That's called operator overloading.
EDIT: Considering paddy's comment to the question (didn't notice myself):
Main reason for your original programme failing was returning a local variable from the stack. That variable runs out of scope on leaving the function, though, so accessing it is actually undefined behaviour. What then happens technically is that the stack's contents (top, size and the pointer) likely get overwritten by next function call that reuses the stack. A problem gone away with the new class + constructor approach proposed above...

Print Object that is pointed to

I try to print values from my object class, but I am unable to properly access the information stored at the pointer. Below I have defined a simple struct.
When compiled, I get an error:
no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::vector<int>')
void PrintNode(Node *node) { cout << node->key << endl; }
struct Node
{
vector<int> key;
int parent;
Node(vector<int> x, int y){ key = x; parent = y; }
void PrintNode(Node* node) { cout << node->key << endl; }
};
I call my PrintNode in my BFS function:
void BFS( vector<int> permutation, int n ) {
vector<Node*>Pointers;
queue<Node*> Queue;
Node* start = new Node(permutation, -1);
Node::PrintNode( start );
Pointers.push_back( start );
}
I don't understand why I am unable to cout the integer vector stored in .key of the node object. I believe that I am dereferencing the pointer correctly with node->key.
The standard library doesn't support direct iostreams output of a vector. But you can easily define such an operation. Just do it with a loop.
std::cout cannot handle raw vectors, you must convert it to an array which is can process first. You can do this using vector's .data() method
Example:
void PrintNode(Node* node) { cout << node->key.data() << endl; }
I try to print values from my object class, but I am unable to properly access the information stored at the pointer. Below I have defined a simple struct.
The simple answer to this question is the fact that std::vector<type, allocator> does not have an overload for the std::ostream::<< operator. Hence when you try to print out the entire vector of keys, it won't work the way you expect it to. I have seen several answers on other posts which suggest overloading the << operator for std::vector but unless you know what you are doing I would avoid doing this for several reasons, one of them being global namespace pollution and the second being incorrect handling of the overloading itself.
Also, please stop doing using namespace std;. It will not help you in any way and just make things worse in the most unexpected ways.
Here are some fixes which may help.
Part 1 - Node struct
struct Node : public std::enable_shared_from_this<Node>
{
std::vector<int> keys;
int parent;
Node(vector<int> x, int y) : keys(x), parent(y){}
Node(const Node& rhs): keys(rhs.keys), parent(rhs.parent) {}
Node(Node&& rhs) noexcept: keys(std::move(rhs.keys)), parent(rhs.parent){}
void PrintNode()
{
for (auto& key : node->keys)
cout << key << "\n";
}
};
Part 2 BFS Code
void BFS(std::vector<int>& permutation, int n )
{
/* I don't see the real value in creating pointers for your case. You can easily live with an instance of the class Node. This also gives you scoped initialization as the pointers vector goes out of scope, your nodes will get deallocated too. at least in the context, you have posted above, that seems desirable.
However, if you insist on creating pointers, you can use smart pointers.
*/
std::vector<std::shared_ptr<Node>> pointers;
std::queue<std::shared_ptr<Node>> queue; // not used??
auto start = std::make_shared<Node>(permutation, -1); // make a shared pointer
/* PrintNode in your code is an instance level function. Invoke it using the scope resolution operators . or ->. If you insist on doing it your way, then declare the function static. However, that has its own quirks and you need to understand static functions before you do this. */
start->PrintNode();
pointers.push_back(std::move(start)); // add your pointer to the vector.
}
That said the code excerpt you have posted makes little sense. I have just provided fixes for the parts you have provided. Does not guarantee that it will work in the larger context you may have at hand.

Assignment operator overload / retrieve function

I'm trying to retrieve an item from a BST for an assignment in class. Some of the provided code I am not allowed to alter. The instructor has created a retrieve function in the driver (which I can't change) that looks like this
static void retrieveItem(char *name)
{
Data const *data;
cout << ">>> retrieve " << name << endl << endl;
if (database->retrieve(name, data))
cout << *data << endl;
else
cout << "not found" << endl;
cout << endl;
}
The function it calls in the BST class looks looks like this (so far). I cannot change the arguments to the function call.
bool BST::retrieve(const char *key, Data const *& data) const
{
int rIndex = 0;
while (rIndex <= capacity)
{
if (strcmp(items[rIndex].data.getName(), key) == 0)
{
data = items[rIndex].data;
return true;
}
else if (strcmp(items[rIndex].data.getName(), key) < 0)
rIndex = (rIndex * 2) + 1;
else if (strcmp(items[rIndex].data.getName(), key) > 0)
rIndex = (rIndex * 2) + 2;
}
return false;
}
There is an array of structs called items that looks like this
struct Item
{
Data data; // the data instance must be specified this way, NOT as a pointer
bool isEmpty = true;
int loc = 0;
};
Item *items;
Finally I have the following assignment overload and copy constructors implemented for the data class (can't change the source file on this one)
Data::Data(const Data& source)
{
strcpy(this->name, source.name);
}
Data& Data::operator=(const Data& data2)
{
strcpy(this->name, data2.name);
return *this;
}
Please correct me if I'm wrong, but it seems like the goal of his retrieve function in the driver is to search for a data object using a key(name), and then copy it into the data argument sent to function. Unfortunately, the line
data = items[rIndex].data;
in my retrieve function doesn't work with a . or an ->]
I'm 90% sure the . is the correct way to access that, but I'm given the error "no suitable conversion type from 'Data' to 'const Data *' exists"
How else could I achieve this without using the assignment overload operator, or my implementation of the overload wrong?
bool BST::retrieve(const char *key, Data const *& data) const
The second argument is a reference to a pointer to const Data, so you must set it to a pointer to items[rIndex].data, not to its value.
Consider the following
void foo(int & out)
{
out = 42;
}
When it is called like so
// ...
int x = 0;
foo(x);
std::cout << x;
42 will be printed, because a reference to x was passed into the function. Your situation is a little different - you are passed a reference to a pointer, so that the caller can retrieve a pointer to the data in a similar way to the above, for example:
int x; // global
// ...
void foo(int *& out)
{
x = 42;
out = &x; // set out to pointer to x
}
int main()
{
int * ptr = nullptr;
foo(ptr); // foo will set ptr to the pointer to x
std::cout << *ptr; // prints 42
}
Again, 42 will be printed. Note the use of the unary ref, &, and deref, *, operators to get a pointer to x and dereference ptr to extract its value.
As an aside, it's not possible to tell how broken your implementation of Data::operator= is without seeing more of the class. As it stands it is broken because it is undefined behaviour to use strcpy on overlapping regions of memory - which will happen if someone tries to assign an object instance to itself (see strcpy). For cases other than self-assignment, it is only correct if the destination of the assignment always has enough space for the string in the source. Otherwise you will write to unallocated memory. Also, if there are any additional member variables, they will need copying too.

In C++, how do I operate on values returned by a function that gives a pointer?

Programming in C++, getting to grips with inheritance. My program makes a class, and then makes a new class that inherits from the first. The first is a vector of doubles, the second a vector of integer coordinates (defined as a structure). Algorithms that worked on the parent class don't work on the child class.
To fix this, I've been changing some functions in the parent class to use memory addresses rather than values, specifically a square brackets [] operator that returns the value of that entry in the vector (or rather, now returns the address of that entry). Changing later parts of the program to use the value at the address given, rather than expect a value immediately, isn't working and I cannot work out why after extensive googling and note-reading. Examples of relevant parts of code are:
The square brackets operators
//access data in vector
double * operator[](int index) {
if(index<0) {
cout<< "Index out of range" << endl;
throw;
}
else if (index>v.size()-1) {
cout<< "Index out of range" << endl;
throw;
}
double *ptr = &v[index];
return ptr;
}
//access data in vector (const)
const double * operator[](int index) const {
if(index<0) {
cout<< "Index out of range" << endl;
throw;
}
else if (index>v.size()-1) {
cout<< "Index out of range" << endl;
throw;
}
const double *ptr = &v[index];
return ptr;
}
and one of the functions that uses the above operator
virtual bool comp(int i, int j) {
if(*v[i]<*v[j]) {
return true;
}
else
return false;
}
I get an error on the uses of
*v[i]<*v[j]
saying that the operator of * must be a pointer, but I'm convinced that the square brackets function is returning a pointer.
Unlike your strange interface, vector's [] returns a reference, not a pointer. So to compare vector elements, you just want v[i] < v[j]. (That's assuming that v is std::vector<double>; your description and other uses of it imply that's the case, but you forgot to include the exact declaration).
By the way, there's no point using if (...) return true; else return false; to convert a boolean expression into exactly the same boolean value. return ...; is much easier to read. More generally, you should lay your code out to make the structure easy to follow; my brain started to melt figuring out what it was supposed to do.

C++ can't establish communication between variables in separate functions

I am making a text-based RPG with C++ and I'm having the same error pop up time and again, and I'm sure I'm doing something fundamentally wrong, but I don't know what. Searches turned up the solution to the specific compiler error, but not anything I can use to fix the code I'm writing.
Question I want answered: How do I use pointers to enable communication of variables between separate functions? In other words, how can I use pointers to point to a variable's value so that I can use and manipulate that value in a function in which it was not declared?
TL;DR version: I'm trying to make my "exp" int variable communicate with outside functions using pointers. I get the error "ISO C++ forbids comparison between pointer and integer [-fpermissive]"
Long version: Here's a bit of the code where I'm having problems:
In file charlvl.cpp:
...
int lvl = 1;
int *exp = 0;//value I want communicated to main()
int str = 0;
int vit = 0;
...
in file fight.cpp (main.cpp):
...
//you've just killed a monster
cout << "\nThe monster drops to the ground." << endl;
cout << "You gained " << expValue << " experience!" << endl;
&exp += expValue;//&exp is the character's experience.
//expValue is the exp gained upon monster death
//*exp (from charlvl.cpp) is the value I want to communicate to here.
It was not declared here, but in charlvl.cpp. How do I establish communication between the declared variable in charlvl.cpp and main() without having to resort to using global variables?
If you defined exp as a global pointer, you don't need to think about the communication thing, you can just simply use it in different functions, but the way you use it is wrong.
&exp += expValue;
should be change to
*exp += expValue;
because * means get that pointer's content to me.
btw, try not defining exp as a pointer may also work.
int exp = 0;
exp += expValue;
This is all based on exp is a global var or global pointer.
if you have defined it in a function like this:
void func()
{
int *expPtr = 0;
int exp = 0
}
And you want to use it in another function
void use()
{
// trying to use expPtr or exp.
}
The ways I know is:
1, use a local var and return it in func(), but be aware that the returned var is only a copy.
int func()
{
int exp = 0;
exp++;
return exp;
}
2, use a local pointer and allocate memory for it, then return the pointer or assign the new memory to a global pointer. But be careful about the memory leak, you need to delete it as soon as you don't use it.
int * func()
{
int *expPtr = 0;
expPtr = new int(2);
return expPtr;
}
You've gotten the & and * operators confused. * turns an int* into an int, while & turns an int* into an int**.
This is what you want:
(*exp) += expValue;
You might want to consider using references.