How to rewrite "node->left->key" replacing -> with "(*)." in C++? - c++14

I'm new to the "->" symbol, so I'm instead replacing it with (*). . However, when I came across the line of code below, I tried replacing it and it didn't work. What am I doing wrong and is there any way to rewrite it?
I keep getting the error that "key" is a pointer and when I rewrite it, it doesn't work. I have triple checked my code, and yet I still don't understand.
struct Node{
int key;
Node *left;
Node *right;
};
Node* createNode(int key){
Node *node = new Node();
(*node).key = key;
(*node).left = NULL;
(*node).right = NULL;
return node;
}
int main(){
Node *root = createNode(1);
(*root).left = createNode(9);
cout << root->left->key; // Correct?
cout << " OR ";
cout << ((*root).left).(*key);
// this is where my code goes wrong and if I remove the (*) from key
// and just leave it like .key it's wrong because key has to be a pointer
return 0;
}
I expect the output to be "9 OR 9" but it doesn't even let me compile past that point.

If you really want to avoid the -> operator, you can write it like this:
cout << (*((*root).left)).key;
... but that's painful to write and painful to read, so it makes a great example of why the -> operator is useful :)

Related

C++ Struct attributes can change within function, but remain unchanged outside scope of function

I'm working on a self imposed challenge which involves implementing a linked list and an append function for it, which is giving me issues seemingly related to variable scope.
The append function loops through each link element until it reads a NULL value and then changes the data value associated with that link to the function input. The test outputs within the function seem to show it is working as intended, but when performing the same test outside the function, even after it is called gives a different output.
template <class T>
struct atom{
T data;
atom<T>* link = NULL;
};
template <class T>
void append_LL(atom<T> first, T input_data){
atom<T>* current_node = &first;
atom<T>* next_node = current_node->link;
int i = 0;
while (i < 4 && next_node != NULL) {
current_node = next_node;
next_node = next_node->link;
i ++;
}
current_node->data = input_data;
current_node->link = (atom<T>*)malloc(sizeof(atom<T>));
cout << "leaving node as: " << current_node->data << endl; //outputs 5
cout << "input nodes data: " << first.data << endl; //outputs 5
}
int main() {
int dd = 5;
atom<int> linked_list;
linked_list.data = 999;
append_LL(linked_list, dd);
cout << linked_list.data << endl; //outputs 999
}
Because you are not sending the same atom. You see the program is making a copy of the linked_list in the main function and sending that copy to the function.
If you want to modify the same linked_list then change
void append_LL(atom<T> first, T input_data){
to
void append_LL(atom<T> &first, T input_data){
That way you are sending the really atom not a copy of it.

C++11 set range based for using structs as elements

Let's say I have a struct like this:
struct Something{
string name;
int code;
};
And a set of Something type:
set<Something> myset;
myset.insert({"aaa",123,});
myset.insert({"bbb",321});
myset.insert({"ccc",213});
What's wrong with this?
for (auto sth : myset){
cout << sth.name;
cout << sth.code;
}
Along the same lines... why can't I modify an element (even when the set contains plain int items) using something like this?
for (auto &sth : myset){
sth=[some value];
}
I know I can do this with vectors and maps. Why not sets?
Thanks!
Modifying an element of a set implies its position in the set's order can change. Because your compiler cannot know what exactly a particular set uses to determine its element's orders. Well, it could, theoretically, but even then it would be nearly impossible to keep track of the rearrangements while iterating through the container. It would make no sense.
What you can do, if you want to modify the elements of a set in such a way that you know will not change their order in a set, you can make the non-ordering members of your struct mutable. Note that if you make a mistake and the set's order is disturbed, any other operations on the set (like a binary search) will give incorrect results after that faulty modification. If you don't want to make members mutable, const_cast is an option, with the same caveats.
To elaborate on my answer above, an example:
#include <iostream>
#include <set>
struct bla
{
std::string name;
int index;
};
bool operator<(const bla& left, const bla& right) { return left.index < right.index; }
int main()
{
std::set<bla> example{{"har", 1}, {"diehar", 2}};
// perfectly fine
for(auto b : example)
std::cout << b.index << ' ' << b.name << '\n';
// perfectly fine - name doesn't influence set order
for(auto& b : example) // decltype(b) == const bla&
const_cast<std::string&>(b.name) = "something";
// better than first loop: no temporary copies
for(const auto& b : example)
std::cout << b.index << ' ' << b.name << '\n';
// using a "universal reference auto&&", mostly useful in template contexts
for(auto&& b : example) // decltype(b) == const bla&
std::cout << b.index << ' ' << b.name << '\n';
// destroying order of the set here:
for(auto& b : example)
const_cast<int&>(b.index) = -b.index;
// anything here relying on an ordered collection will fail
// This includes std::set::find, all the algorithms that depend on uniqueness and/or ordering
// This is pretty much all that will still work, although it may not even be guaranteed
for(auto&& b : example)
std::cout << b.index << ' ' << b.name << '\n';
}
Live code on Coliru.
Note the first const_cast is only ok because the underlying example isn't const in the first place.

return type of decltype(*this)

I think I might have missed the subtlety in move construction because when I change the line Foo copy(*this); to decltype(*this) copy(*this);, I am thoroughly surprised by the output.
I checked it against, clang++-3.5 and g++-4.9, with the same behavior.
Would really appreciate a quick tip from the C++11 guru.
Update: Just forced the compiler to print the type of decltype(*this), it is actually a reference type i.e. Foo&.
class Foo {
public:
Foo(int a): val(a) {}
operator int() { return val; }
auto& operator++() {
val++;
return *this;
}
auto operator++(int) {
//Foo copy(*this);
decltype(*this) copy(*this);
++(*this);
return copy;
}
private:
int val;
};
int main()
{
Foo foo=1;
cout << "foo++ = " << foo++ << "\n";
cout << "foo++ = " << foo++ << "\n";
cout << "foo = " << foo << "\n";
return 0;
}
The output
foo++ = 2
foo++ = 3
foo = 3
There seems to be a confusion as to why decltyp(*this) is Foo& and not Foo in your case. Firstly, think about dereferencing a pointer always resulting in a reference to the pointed to object.
temp = *ptr // this would work if dereferencing returned by value or by reference
*ptr = expr // this would only work if dereferencing results in a reference.
Now decltype(expr) always gives you exactly the same type as the expr. For you *this is of type Foo&.
If you want type deduction without it resulting in a reference use auto instead of decltype, so:
auto copy(*this);
instead of
decltype(*this) copy(*this);
Also I don't know why your question is talking about move construction so much as there is no move involved anywhere.

Singly Linked List using shared_ptr

I was trying to implement singly linked list using share_ptr. Here is the implementation...
Below is the node class...
template<typename T>
class Node
{
public:
T value;
shared_ptr<Node<T>> next;
Node() : value(0), next(nullptr){};
Node(T value) : value(value), next(nullptr){};
~Node() { cout << "In Destructor: " << value << endl; };
};
Below is the linked list class...
template<typename T>
class LinkedList
{
private:
size_t m_size;
shared_ptr<Node<T>> head;
shared_ptr<Node<T>> tail;
public:
LinkedList() : m_size(0), head(nullptr) {};
void push_front(T value)
{
shared_ptr<Node<T>> temp = head;
head = make_shared<Node<T>>(Node<T>(value));
head->next = temp;
m_size++;
if (m_size == 1)
tail = head;
}
void pop_front()
{
if (m_size != 0)
{
// Here I am having doubt------------------------!!!
//shared_ptr<Node<T>> temp = head;
head = head->next;
m_size--;
if (m_size == 0)
tail = nullptr;
}
}
bool empty()
{
return (m_size == 0) ? true : false;
}
T front()
{
if (m_size != 0)
return head->value;
}
};
My question is, am I using the shared_ptr properly for allocating a node? If not, how should I use the shared_ptr to allocate and how should I delete the node in the pop_front method?
I believe this belongs on code review.
Most importantly: Why are you using shared_ptr? shared_ptr means the ownership of an object is unclear. This is not the case for linked lists: Every node owns the next. You can express that using unique_ptr which is easier and more efficient.
pop_front seems to be functioning correctly. You may consider throwing an exception or an assertion instead of doing nothing when using pop_front on an empty list.
front is more problematic. If the list is empty you most likely get a garbage object.
What is the significance of tail? It does not seem to be used for anything and since you cannot go backwards there is no real point to getting the tail.
make_shared<Node<T>>(Node<T>(value)) should be make_shared<Node<T>>(value) instead. make_shared<Node<T>>(value) creates a Node using value as the parameter for the constructor. make_shared<Node<T>>(Node<T>(value)) creates a Node with value as the parameter and then creates a new Node with the temporary Node as parameter and then destroys the first Node.
You are missing the copy and move constructor and assignment and move assignment operators.
After you are satisfied with your list implementation consider using std::forward_list instead.

Having trouble implementing a linked list in c++

I am trying to implement a simple singly linked list of integers which are to be sorted upon insertion in Visual Studio c++ 2010 express.
The problem is that when I create a new node and call the .getValue() function on it, the correct number is returned, however somehow that is being lost when I try calling getValue() on a node already in the list. The node might not be inserted into the list correctly, however I can't find why that would be the case. Some other value which looks like a reference value or something is displayed instead of the correct value.
I added current to the watch window when debugging but was still unable to see any of my variables other than the give value to be inserted. I am new to visual studio so I'm not sure if I'm missing something there. Here is my code:
#include "Node.h";
#include <iostream>
//namespace Linked{
//The first two constructors would be the first in the linked list.
Node::Node(void){
value = 0;
next = 0;
}
Node::Node(int setValue){
value = setValue;
next = 0;
}
Node::Node(int setValue,Node *nextNode){
value = setValue;
next = nextNode;
}
Node * Node::getNext(){
return next;
}
void Node::setNext(Node newNext){
next = &newNext;
}
int Node::getValue(){
return value;
}
bool Node::isEqual(Node check){
return value==check.getValue()&&next == check.getNext();
}
/*
int main(){
int firstInt, secondInt;
std::cin>>firstInt;
Node first = Node(firstInt);
std::cout<<"Enter second int: ";
std::cin>>secondInt;
Node second = Node(secondInt, &first);
std::cout<<"Second: "<<second.getValue()<<"\nFirst: "<<(*second.getNext()).getValue();
system("pause");
}*/
Here is the linked list:
//LinkedList.cpp
LinkedList::LinkedList(void)
{
head = 0;
size = 0;
}
LinkedList::LinkedList(int value)
{
head = &Node(value);
size = 1;
}
void LinkedList::insert(int value){
if(head == 0){
Node newNode = Node(value);
head = &newNode;
std::cout<<"Adding "<<(*head).getValue()<<" as head.\n";
}else{
std::cout<<"Adding ";
Node current = *head;
int numChecked = 0;
while(size<=numChecked && (((*current.getNext()).getValue())<value)){
current = (*(current.getNext()));
numChecked++;
}
if(current.isEqual(*head)&&current.getValue()<value){
Node newNode = Node(value, &current);
std::cout<<newNode.getValue()<<" before the head: "<<current.getValue()<<"\n";
}else{
Node newNode = Node(value,current.getNext());
current.setNext(newNode);
std::cout<<newNode.getValue()<<" after "<<current.getValue()<<"\n";
}
}
size++;
}
void LinkedList::remove(int){
}
void LinkedList::print(){
Node current = *head;
std::cout<<current.getValue()<<" is the head";
int numPrinted = 0;
while(numPrinted<(size-1)){
std::cout<<(current.getValue())<<", ";
current = (*(current.getNext()));
numPrinted++;
}
}
int main(){
int a[5] = {30,20,25,13,2};
LinkedList myList = LinkedList();
int i;
for(i = 0 ; i<5 ; i++){
myList.insert(a[i]);
}
myList.print();
system("pause");
}
Any guidance would be greatly appreciated!
When you create nodes in insert, you're allocating them off the stack, which means that they'll be lost after the function returns.
Get them off the heap with:
Node * newNode=new Node(value);
When you use:
Node newNode=Node(value);
You're allocating that object on the stack, which means that pointers:
&newNode
to it are only valid until that function returns. If you use heap memory this is no longer an issue, but it does mean that you have to implement a destructor for your list which goes through and deletes each node.

Resources