Assignment operator overload / retrieve function - c++

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.

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...

reference vs smart_ptr for dependency inversion

I have two data types, A and B and I have to store the A instance in B in order to refer the A instance in a B method. Both are instantiated in the main function, so the two variables would live for as long as the program is running.
I don't want to make copies, I want to use something like an old fashioned pointer but also I want to follow (and learn) the modern C++ best practices. So what is the most appropriate type to store the A instance in B? (and why?)
I thought that if I want to use a pointer, the best way with modern C++, is using smart pointers, but references seems easier and lighter, so what is the best practice to refer to a variable created in a scope (for example in the main function) and used in another scope (for example a method of a class that has a pointer to that variable), knowing that the scope where that variable is created lives for as long as the class exists (when the stack is deallocated, it will free both the variable and the object that has the variable reference)?
struct A {};
struct B {
A & a;
B(A & a) : a(a) {}
};
int main() {
A a{};
B b{a};
}
or
#include<memory>
struct A {};
struct B {
std::shared_ptr<A> a;
B(auto a) : a(a) {}
};
int main() {
B b{std::make_shared<A>()};
}
The program I'm making is essentially a bunch of test to learn SDL2, I published the repo here https://github.com/antcolag/prova-sdl, B is the App class and A is the EventHandler class instantiated inside the main function.
As #πάντα-ῥεῖ noticed in my particular case the only reasonable way is with smart pointer, because I'm trying to use std::thread and std::atomic, but in a most general case what is the best way to replace the old C style pointers, with a more modern approach, when a variable is allocated in the stack, used by some other object and then deallocated from the stack together with the object?
If i understood the problem, you want to move the instance to a different "owner", with A a; it is posible but it requires a memcpy() if the scope of the instance is deleted. The most easy solution is to contain it in a shared scope, that is bad because it can be a global scope, the next best thing is to pass the reference to the owner (the structure that contains the data). At the end this are cheap solutions if they are applied over and over, modern c++ has a lot of tools for memory control / flow; most of those are pointer based because the data pointer copy is trivial, note that only in combination with std::atomic or a similar lib is suitable for multithreading.
This example shows how a data pointer can be moved and used without any fancy c++, a small note on the pointer idea, in the example the pointer address is not changing as long as it is not deleted, any reference made will persist even if ref_objs order is changed, the data is "on the wild" and the pointer is a number.
#include <iostream>
struct Object {
int num = 69;
};
struct Container {
// Better to use std::vector but
// this shows better what it does
// Olso can be replaced with
// Object * ref_objs [n] if n is fixt
Object ** ref_objs;
uint32_t n_obj;
uint32_t n_obj_max;
void provision_for(uint32_t res_len){
// To initialize data is better to use
// use a method insted of the constructor;
// This alocates n spaces of obj pointers
ref_objs = new Object * [res_len];
n_obj_max = res_len;
n_obj = 0;
}
void clear_all(){
uint32_t i;
for (i=0; i < n_obj; i++){
delete ref_objs[i];
}
delete [] ref_objs;
n_obj = 0;
}
Object * add_obj(){
Object * ret = nullptr;
if (n_obj < n_obj_max){
ref_objs[n_obj] = new Object;
ret = ref_objs[n_obj];
n_obj++;
}
return ret;
}
void del_obj(uint32_t n){
if (n < n_obj - 1){
// keeps them alighned
ref_objs[n] = ref_objs[n_obj];
}
delete ref_objs[n_obj];
n_obj--;
}
int recive_obj(Object * ref){
int res = 1;
if (n_obj < n_obj_max){
ref_objs[n_obj] = ref;
n_obj++;
res = 0;
}
return res;
}
int transfer_to(Container * to, uint32_t item){
int res = 1;
if (to->recive_obj(ref_objs[item]) == 0){
if (item < n_obj - 1){
ref_objs[item] = ref_objs[n_obj - 1];
} else {
ref_objs[item] = nullptr;
}
n_obj --;
res = 0;
}
return res;
}
Object * at (uint32_t at){
return ref_objs[at];
}
Object & operator [](uint32_t at){
// [0] is added to asure the compiler that it
// is a instance and not an array
return ref_objs[at][0];
}
};
int main(void){
Container container_a;
Container container_b;
container_a.provision_for(10);
container_b.provision_for(15);
Object * x = container_a.add_obj();
Object * y = container_a.add_obj();
Object * z = container_b.add_obj();
std::cout << "container_a len -> " << container_a.n_obj << std::endl;
std::cout << "container_b len -> " << container_b.n_obj << std::endl;
y->num = 200;
container_a.transfer_to(&container_b, 0);
container_b[1].num = 400;
std::cout << "container_a obj[0].num -> " << container_a[0].num << std::endl;
std::cout << "container_b obj[0].num -> " << container_b[0].num << std::endl;
std::cout << "container_b obj[1].num -> " << container_b.ref_objs[1]->num << std::endl;
container_a.del_obj(0);
container_a.clear_all();
container_b.clear_all();
return 0;
}
(This example is template suitable, just change all Object with the typename and the instance will be Container<Object> container_a;)

Having trouble with storing a bool array returned by another function

Consider a function that returns a bool array. In the call statement of this function, how do you store the bool array in another bool array?
I can not figure out the syntax. For example, consider this function
void checkoutput(vector<vector<int>>& A, bool op[])
{
int i;
int n = A.size();
bool actualop[n];
actualop = checkiftriangleexists(A);
for (i = 0; i < n; i++)
{
if (actualop[i] == op[i])
{
cout << "Pass" << endl;
}
else cout << "Fail" << endl;
}
}
This function calls checkiftriangleexists(A) that returns a bool array. I want to store this into another bool array called actualop[].
Please help me figure out where I am going wrong.
As mentioned in https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm
you could use static keyword, otherwise the memory assigned to the internal array return by checkiftriangleexists, would be cleaned up after the code is done and is now out of the method zone.
But I prefer to use the memory assigned in the checkoutput function and pass it by reference to checkiftriangleexists and do the job. In this way you don't need to concern about the memory address being cleaned up in checkiftriangleexists method zone. List this:
void checkiftriangleexists(vector<vector<int>>&, bool[]);
void checkoutput(vector<vector<int>> &A, bool op[])
{
...
bool actualop[n];
checkiftriangleexists(A, actualop);
...
}

c++ overload [] operator

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;

Copy part of a class

I want to copy a part of a class to a buffer. I need this to make something that can look if there are changes in a class, and send it over the network to update the changes on the server.
I made a template class that can back-up and restore classes. Now I am making the "look for differences" function. I want that the user can define how big the memory blocks will be. This split the class in parts and takes less data to send.
The problem is that I can't copy a part of the class memory to the heap, I can't get the address correct. If I do "address of the class" + "0x04". Then I don't get the correct addres.
This is an exaple that I made:
testclass test1;
testclass test2;
test1.set(1,1);
test2.set(1,2);
cout << &test1 << " " << (&test1 + 0x04) << endl; //0018FF24 0018FF44
memcpy(&test2,&test1 + 0x04,4);
test2.echo(); //Wrong data!
The header:
class testclass
{
int test,test2;
public:
void set(int a, int b) {test = a, test2 = b;}
void echo() {cout << test << " " << test2 << endl;}
};
I hope someone help me with this problem.
Thanks!
Basically, you can't muck around with pointers like that. You generally can't rely on the compiler to coincidentally put meaningful data there.
If you want the address of members you should write &(test1.test2) not &test1+0x04 because even IF an int is 4 bytes and IF the compiler hasn't padded the structure and IF you or someone else hasn't changed the contents of the class, then &test1+0x04 really means "&test1 plus 4*sizeof(test) bytes", it's another way of reaching (&test1)[4] in terms of pointer-array-equivalence.
Also, you can't memcpy over classes in general and expect meaningful results, unless they are POD.
If you want to compare instances of a class, you should write a function which compares each of the members in turn.
You can't write a general-purpose method for this because C++ is not a reflective language. That means you can't write code which magically knows the names and types of the members of a class.
So, if you want to compare and patch data like this, you will need to do something like this:
struct Foo {
int a;
int b;
void export_differences (std :: ostream & o, const Foo & f) {
if (a != f.a) o << "a " << f.a << " ";
if (b != f.b) o << "b " << f.b << " ";
o << ";";
}
void import_differences (std :: istream & i) {
std :: string s;
while (i >> s) {
if (s == "a") i >> a;
else if (s == "b") i >> b;
else if (s == ";") break;
else throw std :: runtime_error ("bad input");
}
}
};
You will have to write something like this for each class you want to patch.
Where does the magic 0x04 and 4 come from?
If this works, it is just because of a particular alignment and implementation.
Better a more structured way:
class testclass
{
int test,test2;
public:
void set(int a, int b) {test = a, test2 = b;}
void echo() {cout << test << " " << test2 << endl;}
void backup_to(testclass& s)
{ s.test2 = test2; }
bool has_changed_respect(const testclass& s)
{ return s.test2 == test2; }
friend std::ostream& operator<<(std::ostream& s, const testclass& a)
{ return s << "testclass["<<&a<<"]: test="<<a.test<<", test2="<<a.test2<< std::endl; }
};
int main()
{
testclass t1, t2;
t1.set(1,1);
t2.set(3,4);
std::cout << t1 << t2;
t1.backup_to(t2);
std::cout << t2;
t1.set(5,6);
cout << t1 << t2 << t1.is_changed_respect(t2) << std::endl;
return 0;
}
&test1 + 0x04 means to add 4 times the sizeof testclass to the address of test1, and the resulting pointer has type testclass*. It would point to the fifth element of an array whose first element is at the address of test1, except that test1 isn't part of an array, so the addition has undefined behavior.
What you seem to want is to add 4 bytes to the address of test1. You can do that for example with ((char*)&test1) + 4, which results in a pointer of type char*. Beware that the standard doesn't guarantee that sizeof(int) is 4, nor does it guarantee that offsetof(testclass, test2) == sizeof(int).
You're permitted to inspect any object's memory as char* or unsigned char*. But there are some limits on how useful this ability is:
Classes can have padding bytes in them, that can take any values. So just because two objects have different byte values in memory doesn't mean they aren't equal.
Non-POD classes can have pretty much arbitrary "extra stuff" in them, put there by the implementation, and cannot safely be copied byte-wise.
Classes with pointer members often cannot safely be copied byte-wise, and certainly not to another machine over the network.
Even if the class is POD, if you send it over the network then you have to make sure that the class has the same layout on the two machines. This is not necessarily the case if the code was compiled with different options, by different compilers, or for different architectures, but sometimes it is the case.
1) At first, you need your class to be POD. At least you can take out data members to separate structure.
2) Then, if choose your offset granularity = 1, 2, 4 or 2^n bytes as necessary; and determine the type that suits this requirement: 2^n == sizeof(chunk_type). For example, you wish to byte-to-byte comparison, so cast you pointer to _State (or MyClass see #1) to desired type: (char*)this->m_state.
Here is the function, that tries to find the first chunk that differs in both classes, and returns its offset or -1 if no differences found.
class MyClass {
struct _State {
int a,b
};
_State m_state;
public:
typedef char chunk_type;
int next_diff_pos(const MyClass& other, size_t offset = 0) const {
chunk_type *pThis = &m_state,
*pOther = &other.m_state;
if (offset < sizeof(_State)) {
size_t n = offset;
while(*pThis++ == *pOther++ && n < sizeof(_State))
n++;
// We need to test this again, because of ambigous while condition
if (n < sizeof(_State))
return n;
}
return -1;
}
};
PS: Of course, your chunk_type must have == operator defined (this done already for char, int and other scalars).
(I've not tested the code)