How to transfer object to function as it's class'es member - c++

For example: I have class "ListNode" which is linked list member, and i overloaded a [] operator for List class itself, but every time i need to get data from a node, i need to write list[0]->getData() or if I want to set new data, I need to write list[0]->setData(*somedata*).
But I want to make it be able to work like for example like list[0] = 5, so first Node's data is setted to 6. Same with functions. What should I do if I have Node which has int data, and I need to transfer it's data to a function, but without writing Node->getData() all the time?

You can make your operator[] return a reference to the element you want to access.
The example below is a simplified version of what would be a proper solution, including a const version for the operator[].
[Demo]
#include <iostream> // cout
#include <stdexcept> // range_error
struct Node
{
int value{};
Node* next{};
int& operator[](size_t pos)
{
if (pos == 0) { return this->value; }
else if (next == nullptr) { throw std::range_error{"out of bounds"}; }
else { return (*next)[pos - 1]; }
}
};
int main()
{
Node n5{5, nullptr};
Node n4{4, &n5};
Node n3{3, &n4};
Node n2{2, &n3};
Node list{1, &n2};
try
{
std::cout << "list[3]: " << list[3] << "\n";
list[3] = 25;
std::cout << "list[3]: " << list[3] << "\n";
std::cout << "list[13]: " << list[13] << "\n";
}
catch (const std::exception& exc)
{
std::cout << "Error: " << exc.what() << ".\n";
}
}

Related

Integer pointer only has correct value if I print it

I am implementing my own smart_pointer, which counts the references to the thing it points to. Here is my implementation so far:
#pragma once
#include <iostream>
template <typename T>
class smart_pointer{
T* pointer;
int* cnt;
public:
smart_pointer<T>(T *el): pointer(el) { int i = 1; cnt = &i; }; //
smart_pointer<T>(const smart_pointer<T>& other): pointer(other.pointer) {
// std::cout << ", *(other.cnt): " << *(other.cnt);
cnt = other.cnt;
(*cnt)++;
} // Copy-constructor
int counter(){
int c = *cnt;
return c;
}
};
In main.cpp, I did the following:
int main(){
// smart_pointer_examples();
std::string h("hello");
smart_pointer<std::string> p(&h);
std::cout << "p: " << p.counter();
smart_pointer<std::string> q(p);
std::cout << ", q: " << q.counter() << std::endl;
return 0;
}
The problem is that that outputs p: 1, q: 6487781. After a lot of time trying to find the issue by debugging and printing stuff, I found something that fixed my issue: By adding std::cout << ", *(other.cnt): " << *(other.cnt); somewhere in my copy-constructor, the output becomes p: 1, *(other.cnt): 1, q: 2, which is the desired behaviour. I can't for the life of me think of why printing the counter would change anything.
Edit: Also, if I only do *(other.cnt) without std::cout, the same problem that I started with happens.
You made a small mistake in implementing your idea.
I will not comment on the design of your smart pointer implementation.
The problem is that you implemented your counter as a pointer. That is wrong.
And, you are dereferencing a local variable. That is a semantic bug. The result is undefined. The value of the counter will be indeterminate. Additionally you should initialize your class members.
If we fix both, then your code will look like:
#pragma once
#include <iostream>
template <typename T>
class smart_pointer {
T* pointer{};
int cnt{};
public:
smart_pointer<T>(T* el) : pointer(el) { cnt = 1; }; //
smart_pointer<T>(const smart_pointer<T>& other) : pointer(other.pointer) {
// std::cout << ", *(other.cnt): " << *(other.cnt);
cnt = other.cnt;
cnt++;
} // Copy-constructor
int counter() const {
return cnt;
}
};
int main() {
// smart_pointer_examples();
std::string h("hello");
smart_pointer<std::string> p(&h);
std::cout << "p: " << p.counter();
smart_pointer<std::string> q(p);
std::cout << ", q: " << q.counter() << std::endl;
return 0;
}

Access map element via pointer in C++

I switched from c to c++ recently and just can't figure out what I'm doing wrong here.
I would like to access and set the member of a map via another function.
Here is my example which you can just copy to cpp.sh or so if you like
#include <iostream>
#include <map>
using namespace std;
struct test{
int i;
int j;
};
void addValues(test* val){
if (val == NULL){
val = new test();
cout<<"new";
}
val->i = 10;
val->j = 12;
}
void printVal(test* val){
cout<<"finish " << val->i << " " << val->j;
}
int main()
{
map<string, test*> bla = {{"test1",NULL}};
addValues(bla.at("test1"));
printVal(bla.at("test1"));
return 0;
}
code from my project is a little bit more complex but it's basically this problem. I created a test in addValues() and have not deleted it. Why am I not able to print this value in printVal()? What am I missing?
Thanks in advance!
Parameters are passed by value. Pointers are no exception to that. Your addValues modifies a local copy of the pointer when a nullptr is passed. Modifying that local copy does not affect the pointer in the map. Pass the pointer by reference:
void addValues(test*& val){
if (val == nullptr){
val = new test();
cout<<"new";
}
val->i = 10;
val->j = 12;
}
Or better yet, do not use raw pointers in the first place. Moreover, consider to write a constructor that initializes the members of test instead of relying on the caller to initialize them.
Example :
#include <iostream>
#include <map>
//using namespace std; NO teach yourself not to do this.
struct test
{
int i = 0; // <== in c++ you can initialize values of structs
int j = 0;
};
// this instead of printVal
std::ostream& operator<<(std::ostream& os, const test& t)
{
os << "i = " << t.i << ", j = " << t.j << "\n";
return os;
}
int main()
{
std::map<std::string, test> map =
{
{"test1",{1,1}},
{"test2",{2,2}},
};
// loop over all entries in the map
// range based for loop.
// each entry in the map is a key,value pair (not they key, not the value but a pair)
// https://en.cppreference.com/w/cpp/language/range-for
std::cout << "range based for over keyvalue pairs\n";
for (const auto& kv : map)
{
// note kv.second is where we use operator<< from earlier.
std::cout << "Key : " << kv.first << ", value : " << kv.second << "\n";
}
std::cout << "\n";
// structured bindings make code more readable
// https://en.cppreference.com/w/cpp/language/structured_binding
std::cout << "range based for using structured bindings \n";
for (const auto& [key, value] : map)
{
std::cout << "Key : " << key << ", value : " << value <<"\n";
}
std::cout << "\n";
return 0;
}

Linked list doesn't work when I tried to extract first element

I'm trying to use my own list with a class called "NameCard" which has two variables, name and phone.
However, complier crushed when I use LFirst(LData pData).
It worked with simple int type list.
any feedback would be greatly appreciated
Here is my code.
Class name: ArrayList.cpp
int ArrayList::LFirst(LData* pData)
{
if (numOfData == 0)
return 0;
curPosition = 0;
*pData = arr[0];
return 1;
}
Class name: NameCard.cpp
NameCard::NameCard()
{
}
NameCard::NameCard(const char* iName, const char* iPhone)
{
strcpy_s(name, iName);
strcpy_s(phone, iPhone);
}
void NameCard::ShowNameCardInfo()
{
std::cout << "Name: " << name << ", phone: " << phone << std::endl;
}
int NameCard::NameCompare(char* iName)
{
return strcmp(name, iName);
}
void NameCard::ChangePhoneNum(char* iPhone)
{
strcpy_s(phone, iPhone);
}
Class name: NameCardImplementation.cpp
#include <iostream>
#include "ArrayList.h"
#include "NameCard.h"
int main()
{
ArrayList list;
NameCard *pData(NULL);
NameCard nc1("Alice", "010-1111-2222");
NameCard nc2("Brandon", "010-2222-3333");
NameCard nc3("Jack", "010-3333-4444");
list.LInsert(nc1);
list.LInsert(nc2);
list.LInsert(nc3);
//nc1.ShowNameCardInfo();
//list.arr[0].ShowNameCardInfo();
//std::cout << list.LCount() << std::endl;
int a = list.LFirst(pData);
std::cout << a << std::endl;
//if (list.LFirst(pData))
//{
// pData->ShowNameCardInfo();
//}
}
Crash is due to null pointer access in ArrayList::LFirst.
From the limited code you have pasted, I see that there is no memory created for pData.
NameCard *pData(NULL);
Are you attaching the memory for pData anywhere else in your code?

Data placed into array correctly but is not there when array is printed

I'm implementing my own hash table and I am running into the following problem: when I insert my node(s) into the table, they are not printed out when I loop through the array. I am using an array of arrays as the underlying data structure and the logic is as follows:
I pass my node to an insert function. This function, based on the
type of data in my node, calls the appropriate hash function provided
by the C++ STL.
Then, I mod the hash value returned by the size of
my hash table and use that to determine which array to place the
node.
I also have an array of arrays of booleans (the same size as my
hash table) that I use to check whether a specific spot in my hash
table already has data in it.
If it does, I simply keep looping till
an empty spot is found.
Like I said before, the problem is that the data is inputed correctly into the array (I've checked that with print statements), but when I print the array, nothing is outputted. I have also checked if my object is being constructed correctly (again, with print statements), but everything is looking fine. I've included the full code below. Any help would be greatly appreciated!
///////START OF NODE.H///////////
#ifndef NODE_H
#define NODE_H
#include <iostream>
template <typename T>
class HashTable;
template <typename T>
class Node
{
friend class HashTable<T>;
private:
T data;
public:
Node(T Data): data(Data)
{
std::cout << "In the node constructor" << std::endl;
}
Node()
{
decltype(data) {};
}
T getData() const
{
return data;
}
};
#endif
//////////////////////END OF NODE.H////////////////////
/////START OF HASHTABLE.H///////
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include "Node.h"
#include <iostream>
#include <array>
#include <functional>
#include <typeinfo>
#include <string>
const int TABLE_SIZE=5;
template <typename T>
class HashTable
{
private:
std::array<std::array<Node<T>, TABLE_SIZE>, TABLE_SIZE> hashTable;
std::array<std::array<bool, TABLE_SIZE>, TABLE_SIZE> spots;
public:
HashTable()
{
for(int index=0;index<spots.size();++index)
{
for(int position=0;position<spots.at(index).size();++position)
{
spots.at(index).at(position)=false;
}
}
}
int hashFunction(Node<T> Node)
{
auto key=Node.getData();
std::hash<decltype(Node.getData())> hash_function {};
int hash=hash_function(key);
if(hash < 0)
{
hash*=-1;
}
//std::cout << "The hash value return by the STL hash function for the key " << key << " is " << hash << std::endl;
if(hash > TABLE_SIZE)
{
hash%=TABLE_SIZE;
}
std::cout << "The hash value for the key " << key << " is " << hash << std::endl;
return hash;
}
void insert(Node<T> Node)
{
int hashValue=hashFunction(Node);
auto location=hashTable.at(hashValue);
std::cout << "Going to insert " << Node.getData() << std::endl;
for(int index=0;index<location.size();++index)
{
if(spots.at(hashValue).at(index)==false)
{
std::cout << "Found a spot that is not taken!" << std::endl;
std::cout << "The size of the data at the spot in the array before we insert is: " << location.at(index).getData().size() << std::endl;
location.at(index)=Node;
std::cout << "The size of the data at the spot in the array after we insert is: " << location.at(index).getData().size() << std::endl;
std::cout << "The data that is in the spot in the array: " << location.at(index).getData() << std::endl;
std::cout << std::endl;
spots.at(hashValue).at(index)=true;
break;
}
}
}
bool contains(Node<T> Node)
{
int hashValue=hashFunction(Node);
auto location=hashTable.at(hashValue);
auto result=find_if(begin(location), end(location), [Node] (const auto & element) {return element.getData()==Node.getData();});
if(result!=end(location))
{
return true;
}
return false;
}
int getSize() const
{
int size {};
for(int index=0;index<hashTable.size();++index)
{
size+=hashTable.at(index).size();
}
return size;
}
void print()
{
std::cout << "In the print function" << std::endl;
for(int index=0;index<hashTable.size();++index)
{
//std::cout << hashTable.at(index).size() << std::endl;
for(int position=0;position<hashTable.at(index).size();++position)
{
std::cout << hashTable.at(index).at(position).getData().size() << std::endl;
}
}
/*
for(int index=0;index<spots.size();++index)
{
for(int position=0;position<spots.at(index).size();++position)
{
if(spots.at(index).at(position)==true)
{
std::cout << "There should be some data here" << std::endl;
}
}
}
*/
}
};
#endif
////////////END OF HASHTABLE.H//////////
////////////START OF MAIN.CPP///////////
#include "HashTable.h"
#include <cstdlib>
#include <random>
#include <algorithm>
using namespace std;
int main()
{
HashTable<string> hash_table;
hash_table.insert(Node<string>("Java"));
hash_table.insert(Node<string>("C++"));
hash_table.insert(Node<string>("C#"));
hash_table.insert(Node<string>("Latex"));
hash_table.insert(Node<string>("Python"));
}
/////////////END OF MAIN.CPP/////////////
One error is in your insert(Node<T> Node) function on these line:
auto location=hashTable.at(hashValue);
//...
location.at(index) = Node;
The location should be a reference not a copy. What is happening is that you're making changes to a local location, and not the actual location that the hash table uses. Thus none of your changes "stick".
The line above should be this:
auto& location=hashTable.at(hashValue); // <-- note that auto is a reference
//...
location.at(index) = Node;
Now you are assigning the returned reference to a reference.
Also, I highly recommend you use a debugger, as this error could have been easily diagnosed if you stepped through your code to see what was being done.
in HashTable::insert this line:
auto location = hashTable.at(hashValue);
makes a copy of a Node. You then operate on and store in the copy, not the node in hashTable. Taking a reference to the node
auto & location = hashTable.at(hashValue);
should fix it.

Recursive function does not fully recurse object / sub-objects

I have a recursive function find() that tries to find a item with an given ID. Below I extracted the relevant parts from the class to make an example to compile:
#include <iostream>
#include <cstdarg>
#include <cstdio>
#include <string>
#include <vector>
class Item {
private:
std::vector<Item> subitems;
public:
std::wstring id;
public:
Item()
: subitems(0), id(L"") {}
Item(const Item& rhs)
: subitems(rhs.subitems.size()) {
for (std::size_t i = 0; i < rhs.subitems.size(); ++i)
subitems[i] = rhs.subitems[i];
id = rhs.id;
}
Item& operator==(const Item& rhs) {
if (this != &rhs) {
for (std::size_t i = 0; i < rhs.subitems.size(); ++i)
subitems[i] = rhs.subitems[i];
id = rhs.id;
}
return *this;
}
std::vector<Item> getSubitems() {
return subitems;
}
Item addSubitems(Item * item ...) {
va_list args;
va_start(args, item);
for (Item * arg = item; arg != NULL; arg = va_arg(args, Item *)) {
subitems.push_back(*item);
}
va_end(args);
return *this;
}
Item addSubitems(std::vector<Item>& items) {
for (typename std::vector<Item>::value_type &item : items) {
subitems.push_back(item);
}
return *this;
}
static Item * find(int id, std::vector<Item>& items) {
std::wstring id_str = std::to_wstring(id);
std::wcout << "--> find id=" << id_str << std::endl;
std::wcout << "size of items=" << items.size() << std::endl;
for (typename std::vector<Item>::value_type &c : items) {
std::wcout << "it .. cur id=" << c.id << std::endl;
if (!c.id.empty() && c.id == id_str) {
std::wcout << "==> found" << std::endl;
return &c;
}
if (!(c.getSubitems()).empty()) {
std::wcout << "-> find " << id << " in subitems" << std::endl;
std::vector<Item> subcls = c.getSubitems();
std::wcout << "size of subitems=" << subcls.size() << std::endl;
Item * sub = find(id, subcls);
if (sub != NULL) {
std::wcout << "==> found in subitems" << std::endl;
return sub;
}
}
}
return NULL;
}
};
int main() {
Item c1;
c1.id = L"0";
Item c2;
c2.id = L"1";
Item c3;
c3.id = L"2";
Item c4;
c4.id = L"3";
//std::vector<Item> cll4({c4});
//std::vector<Item> cll3({c3});
//std::vector<Item> cll2({c2});
c3.addSubitems(&c4, NULL);
c2.addSubitems(&c3, NULL);
c1.addSubitems(&c2, NULL);
//c1.addSubitems(cll2);
//c2.addSubitems(cll3);
//c3.addSubitems(cll4);
std::vector<Item> items({c1});
Item * c = Item::find(2, items);
std::wcout
<< "Found item="
<< ((c != NULL && c == &c3) ? "true" : "false") << std::endl;
std::wcout
<< ((c != NULL) ? c->id : L"") << std::endl;
return 0;
}
I create a few Items and add sub-Items to them. Now I want to be able to lookup an ID of an item and return the found item or sub-item object by using the recursive find() method.
If I add items with the addSubitems() (with variable args), it will find the item but doesn't return a (valid) item object. If I use the addSubitems method by passing a vector of items the find() method does not recurse fully all subitems.
Actually I am sitting on this problem now the last 4 hours and I am out of ideas, it might be a simple thing I oversee or miss. I added the copy constructor / and assignment operator afterwords (just to see if there are changes in behaviour), but no. Do not worry about the item ID being a string type (the reason is for later serialization), this class is in its early stages so I for now I chose a string type.
Could somebody please point me the flaws/problems to get this class straight! Thanks so much in advance!
Well, one problem with the "it will find the item but doesn't return a (valid) item object." is:
You send Item* to the addSubItems method and then you add a (*Item) to the vector;
This will initialize a copy c'tor, so later on, when you do is &c == &c3, obviously it would be false, since while the objects are INDEED identical, the addresses would not be since they are copies of one another.
Not that I understand why you would want to copy but the solution would be to either test
if (c == c3) -> activating the Item operator ==
OR allocate the members, save a
std::vector<Item*> subitems;
and then ask if (c == c3) -> asking about the addresses